Loading packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt +10 −4 Original line number Diff line number Diff line Loading @@ -29,12 +29,18 @@ import javax.inject.Inject * Provides a shortcut to start an activity from [QSTileUserActionInteractor]. It supports keyguard * dismissing and tile from-view animations. */ interface QSTileIntentUserInputHandler { fun handle(view: View?, intent: Intent) fun handle(view: View?, pendingIntent: PendingIntent) } @SysUISingleton class QSTileIntentUserInputHandler class QSTileIntentUserInputHandlerImpl @Inject constructor(private val activityStarter: ActivityStarter) { constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInputHandler { fun handle(view: View?, intent: Intent) { override fun handle(view: View?, intent: Intent) { val animationController: ActivityLaunchAnimator.Controller? = view?.let { ActivityLaunchAnimator.Controller.fromView( Loading @@ -46,7 +52,7 @@ constructor(private val activityStarter: ActivityStarter) { } // TODO(b/249804373): make sure to allow showing activities over the lockscreen. See b/292112939 fun handle(view: View?, pendingIntent: PendingIntent) { override fun handle(view: View?, pendingIntent: PendingIntent) { if (!pendingIntent.isActivity) { return } Loading packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt +7 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.systemui.qs.tiles.di import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerImpl import com.android.systemui.qs.tiles.impl.custom.di.CustomTileComponent import com.android.systemui.qs.tiles.viewmodel.QSTileConfig import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider Loading Loading @@ -45,4 +47,9 @@ interface QSTilesModule { @Multibinds fun tileViewModelMap(): Map<String, QSTileViewModel> @Binds fun bindQSTileConfigProvider(impl: QSTileConfigProviderImpl): QSTileConfigProvider @Binds fun bindQSTileIntentUserInputHandler( impl: QSTileIntentUserInputHandlerImpl ): QSTileIntentUserInputHandler } packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt +1 −1 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ class QSTileIntentUserInputHandlerTest : SysuiTestCase() { @Before fun setup() { MockitoAnnotations.initMocks(this) underTest = QSTileIntentUserInputHandler(activityStarted) underTest = QSTileIntentUserInputHandlerImpl(activityStarted) } @Test Loading packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt 0 → 100644 +52 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.tiles.base.actions import android.app.PendingIntent import android.content.Intent import android.view.View /** * Fake implementation of [QSTileIntentUserInputHandler] interface. Consider using this alongside * [QSTileIntentUserInputHandlerSubject]. */ class FakeQSTileIntentUserInputHandler : QSTileIntentUserInputHandler { val handledInputs: List<Input> get() = mutableInputs private val mutableInputs = mutableListOf<Input>() override fun handle(view: View?, intent: Intent) { mutableInputs.add(Input.Intent(view, intent)) } override fun handle(view: View?, pendingIntent: PendingIntent) { mutableInputs.add(Input.PendingIntent(view, pendingIntent)) } sealed interface Input { data class Intent(val view: View?, val intent: android.content.Intent) : Input data class PendingIntent(val view: View?, val pendingIntent: android.app.PendingIntent) : Input } } val FakeQSTileIntentUserInputHandler.intentInputs get() = handledInputs.mapNotNull { it as? FakeQSTileIntentUserInputHandler.Input.Intent } val FakeQSTileIntentUserInputHandler.pendingIntentInputs get() = handledInputs.mapNotNull { it as? FakeQSTileIntentUserInputHandler.Input.PendingIntent } packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt 0 → 100644 +76 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.tiles.base.actions import com.google.common.truth.FailureMetadata import com.google.common.truth.Subject import com.google.common.truth.Truth /** [Truth] [Subject] to assert inputs handled by [FakeQSTileIntentUserInputHandler] */ class QSTileIntentUserInputHandlerSubject private constructor( failureMetadata: FailureMetadata, private val subject: FakeQSTileIntentUserInputHandler ) : Subject(failureMetadata, subject) { fun handledOneIntentInput( intentAssertions: (FakeQSTileIntentUserInputHandler.Input.Intent) -> Unit = {}, ) { // check that there are no other inputs check("handledInputs").that(subject.handledInputs).hasSize(1) // check there is an intent input check("intentInputs").that(subject.intentInputs).hasSize(1) intentAssertions(subject.intentInputs.first()) } fun handledOnePendingIntentInput( intentAssertions: (FakeQSTileIntentUserInputHandler.Input.PendingIntent) -> Unit = {}, ) { // check that there are no other inputs check("handledInputs").that(subject.handledInputs).hasSize(1) // check there is a pending intent input check("intentInputs").that(subject.pendingIntentInputs).hasSize(1) intentAssertions(subject.pendingIntentInputs.first()) } fun handledNoInputs() { check("handledInputs").that(subject.handledInputs).isEmpty() } companion object { /** * [Truth.assertThat]-like factory to initialize the assertion. Example: * ``` * assertThat(inputHandler).handledOneIntentInput { * assertThat(it.intent.action).isEqualTo("action.Test") * } * ``` */ fun assertThat( handler: FakeQSTileIntentUserInputHandler ): QSTileIntentUserInputHandlerSubject = Truth.assertAbout { failureMetadata: FailureMetadata, subject: FakeQSTileIntentUserInputHandler -> QSTileIntentUserInputHandlerSubject(failureMetadata, subject) } .that(handler) } } Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt +10 −4 Original line number Diff line number Diff line Loading @@ -29,12 +29,18 @@ import javax.inject.Inject * Provides a shortcut to start an activity from [QSTileUserActionInteractor]. It supports keyguard * dismissing and tile from-view animations. */ interface QSTileIntentUserInputHandler { fun handle(view: View?, intent: Intent) fun handle(view: View?, pendingIntent: PendingIntent) } @SysUISingleton class QSTileIntentUserInputHandler class QSTileIntentUserInputHandlerImpl @Inject constructor(private val activityStarter: ActivityStarter) { constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInputHandler { fun handle(view: View?, intent: Intent) { override fun handle(view: View?, intent: Intent) { val animationController: ActivityLaunchAnimator.Controller? = view?.let { ActivityLaunchAnimator.Controller.fromView( Loading @@ -46,7 +52,7 @@ constructor(private val activityStarter: ActivityStarter) { } // TODO(b/249804373): make sure to allow showing activities over the lockscreen. See b/292112939 fun handle(view: View?, pendingIntent: PendingIntent) { override fun handle(view: View?, pendingIntent: PendingIntent) { if (!pendingIntent.isActivity) { return } Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt +7 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.systemui.qs.tiles.di import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerImpl import com.android.systemui.qs.tiles.impl.custom.di.CustomTileComponent import com.android.systemui.qs.tiles.viewmodel.QSTileConfig import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider Loading Loading @@ -45,4 +47,9 @@ interface QSTilesModule { @Multibinds fun tileViewModelMap(): Map<String, QSTileViewModel> @Binds fun bindQSTileConfigProvider(impl: QSTileConfigProviderImpl): QSTileConfigProvider @Binds fun bindQSTileIntentUserInputHandler( impl: QSTileIntentUserInputHandlerImpl ): QSTileIntentUserInputHandler }
packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt +1 −1 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ class QSTileIntentUserInputHandlerTest : SysuiTestCase() { @Before fun setup() { MockitoAnnotations.initMocks(this) underTest = QSTileIntentUserInputHandler(activityStarted) underTest = QSTileIntentUserInputHandlerImpl(activityStarted) } @Test Loading
packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt 0 → 100644 +52 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.tiles.base.actions import android.app.PendingIntent import android.content.Intent import android.view.View /** * Fake implementation of [QSTileIntentUserInputHandler] interface. Consider using this alongside * [QSTileIntentUserInputHandlerSubject]. */ class FakeQSTileIntentUserInputHandler : QSTileIntentUserInputHandler { val handledInputs: List<Input> get() = mutableInputs private val mutableInputs = mutableListOf<Input>() override fun handle(view: View?, intent: Intent) { mutableInputs.add(Input.Intent(view, intent)) } override fun handle(view: View?, pendingIntent: PendingIntent) { mutableInputs.add(Input.PendingIntent(view, pendingIntent)) } sealed interface Input { data class Intent(val view: View?, val intent: android.content.Intent) : Input data class PendingIntent(val view: View?, val pendingIntent: android.app.PendingIntent) : Input } } val FakeQSTileIntentUserInputHandler.intentInputs get() = handledInputs.mapNotNull { it as? FakeQSTileIntentUserInputHandler.Input.Intent } val FakeQSTileIntentUserInputHandler.pendingIntentInputs get() = handledInputs.mapNotNull { it as? FakeQSTileIntentUserInputHandler.Input.PendingIntent }
packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerSubject.kt 0 → 100644 +76 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.tiles.base.actions import com.google.common.truth.FailureMetadata import com.google.common.truth.Subject import com.google.common.truth.Truth /** [Truth] [Subject] to assert inputs handled by [FakeQSTileIntentUserInputHandler] */ class QSTileIntentUserInputHandlerSubject private constructor( failureMetadata: FailureMetadata, private val subject: FakeQSTileIntentUserInputHandler ) : Subject(failureMetadata, subject) { fun handledOneIntentInput( intentAssertions: (FakeQSTileIntentUserInputHandler.Input.Intent) -> Unit = {}, ) { // check that there are no other inputs check("handledInputs").that(subject.handledInputs).hasSize(1) // check there is an intent input check("intentInputs").that(subject.intentInputs).hasSize(1) intentAssertions(subject.intentInputs.first()) } fun handledOnePendingIntentInput( intentAssertions: (FakeQSTileIntentUserInputHandler.Input.PendingIntent) -> Unit = {}, ) { // check that there are no other inputs check("handledInputs").that(subject.handledInputs).hasSize(1) // check there is a pending intent input check("intentInputs").that(subject.pendingIntentInputs).hasSize(1) intentAssertions(subject.pendingIntentInputs.first()) } fun handledNoInputs() { check("handledInputs").that(subject.handledInputs).isEmpty() } companion object { /** * [Truth.assertThat]-like factory to initialize the assertion. Example: * ``` * assertThat(inputHandler).handledOneIntentInput { * assertThat(it.intent.action).isEqualTo("action.Test") * } * ``` */ fun assertThat( handler: FakeQSTileIntentUserInputHandler ): QSTileIntentUserInputHandlerSubject = Truth.assertAbout { failureMetadata: FailureMetadata, subject: FakeQSTileIntentUserInputHandler -> QSTileIntentUserInputHandlerSubject(failureMetadata, subject) } .that(handler) } }