Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt +114 −4 Original line number Diff line number Diff line Loading @@ -16,32 +16,45 @@ package com.android.systemui.qs.tiles.base.actions import android.app.PendingIntent import android.content.ComponentName import android.content.Intent import android.content.pm.ActivityInfo import android.content.pm.PackageManager import android.content.pm.PackageManager.ResolveInfoFlags import android.content.pm.ResolveInfo import android.os.UserHandle import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.plugins.ActivityStarter import com.android.systemui.util.mockito.argThat import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatcher import org.mockito.Mock import org.mockito.Mockito.any import org.mockito.Mockito.eq import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) class QSTileIntentUserInputHandlerTest : SysuiTestCase() { @Mock private lateinit var activityStarted: ActivityStarter @Mock private lateinit var packageManager: PackageManager @Mock private lateinit var activityStarter: ActivityStarter lateinit var underTest: QSTileIntentUserInputHandler @Before fun setup() { MockitoAnnotations.initMocks(this) underTest = QSTileIntentUserInputHandlerImpl(activityStarted) underTest = QSTileIntentUserInputHandlerImpl(activityStarter, packageManager, user) } @Test Loading @@ -50,6 +63,103 @@ class QSTileIntentUserInputHandlerTest : SysuiTestCase() { underTest.handle(null, intent) verify(activityStarted).postStartActivityDismissingKeyguard(eq(intent), eq(0), any()) verify(activityStarter).postStartActivityDismissingKeyguard(eq(intent), eq(0), any()) } @Test fun testPassesActivityPendingIntentToStarterAsPendingIntent() { val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } underTest.handle(null, pendingIntent, true) verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any()) } @Test fun testPassesActivityPendingIntentToStarterAsPendingIntentWhenNotRequestingActivityStart() { val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } underTest.handle(null, pendingIntent, false) verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any()) } @Test fun testPassNonActivityPendingIntentAndRequestStartingActivity_findsIntentAndStarts() { val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(false) whenever(creatorPackage).thenReturn(ORIGINAL_PACKAGE) } setUpQueryResult(listOf(createActivityInfo(testResolvedComponent, exported = true))) underTest.handle(null, pendingIntent, true) val expectedIntent = Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) .setPackage(null) .addFlags( Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED ) .setComponent(testResolvedComponent) verify(activityStarter) .postStartActivityDismissingKeyguard( argThat(IntentMatcher(expectedIntent)), eq(0), any() ) } @Test fun testPassNonActivityPendingIntentAndDoNotRequestStartingActivity_doesNotStartActivity() { val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(false) } underTest.handle(null, pendingIntent, false) verify(activityStarter, never()) .postStartActivityDismissingKeyguard(any(Intent::class.java), eq(0), any()) } private fun createActivityInfo( componentName: ComponentName, exported: Boolean = false, ): ActivityInfo { return ActivityInfo().apply { packageName = componentName.packageName name = componentName.className this.exported = exported } } private fun setUpQueryResult(infos: List<ActivityInfo>) { `when`( packageManager.queryIntentActivitiesAsUser( any(Intent::class.java), any(ResolveInfoFlags::class.java), eq(user.identifier) ) ) .thenReturn(infos.map { ResolveInfo().apply { activityInfo = it } }) } private class IntentMatcher(intent: Intent) : ArgumentMatcher<Intent> { private val expectedIntent = intent override fun matches(argument: Intent?): Boolean { return argument?.action.equals(expectedIntent.action) && argument?.`package`.equals(expectedIntent.`package`) && argument?.component?.equals(expectedIntent.component)!! && argument?.categories?.equals(expectedIntent.categories)!! && argument?.flags?.equals(expectedIntent.flags)!! } } companion object { private const val ORIGINAL_PACKAGE = "original_pkg" private const val TEST_PACKAGE = "test_pkg" private const val TEST_COMPONENT_CLASS_NAME = "test_component_class_name" private val testResolvedComponent = ComponentName(TEST_PACKAGE, TEST_COMPONENT_CLASS_NAME) private val user = UserHandle.of(0) } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt +11 −28 Original line number Diff line number Diff line Loading @@ -18,42 +18,25 @@ package com.android.systemui.qs.tiles.impl.alarm.domain.interactor import android.app.AlarmManager.AlarmClockInfo import android.app.PendingIntent import android.content.Intent import android.provider.AlarmClock import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx.click import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mockito.verify @SmallTest @RunWith(AndroidJUnit4::class) class AlarmTileUserActionInteractorTest : SysuiTestCase() { private lateinit var activityStarter: ActivityStarter private lateinit var intentCaptor: ArgumentCaptor<Intent> private lateinit var pendingIntentCaptor: ArgumentCaptor<PendingIntent> lateinit var underTest: AlarmTileUserActionInteractor @Before fun setup() { activityStarter = mock<ActivityStarter>() intentCaptor = ArgumentCaptor.forClass(Intent::class.java) pendingIntentCaptor = ArgumentCaptor.forClass(PendingIntent::class.java) underTest = AlarmTileUserActionInteractor(activityStarter) } private val inputHandler = FakeQSTileIntentUserInputHandler() private val underTest = AlarmTileUserActionInteractor(inputHandler) @Test fun handleClickWithDefaultIntent() = runTest { Loading @@ -62,21 +45,21 @@ class AlarmTileUserActionInteractorTest : SysuiTestCase() { underTest.handleInput(click(inputModel)) verify(activityStarter) .postStartActivityDismissingKeyguard(capture(intentCaptor), eq(0), nullable()) assertThat(intentCaptor.value.action).isEqualTo(AlarmClock.ACTION_SHOW_ALARMS) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { assertThat(it.intent.action).isEqualTo(AlarmClock.ACTION_SHOW_ALARMS) } } @Test fun handleClickWithPendingIntent() = runTest { val expectedIntent: PendingIntent = mock<PendingIntent>() val expectedIntent = mock<PendingIntent>() val alarmInfo = AlarmClockInfo(1L, expectedIntent) val inputModel = AlarmTileModel.NextAlarmSet(true, alarmInfo) underTest.handleInput(click(inputModel)) verify(activityStarter) .postStartActivityDismissingKeyguard(capture(pendingIntentCaptor), nullable()) assertThat(pendingIntentCaptor.value).isEqualTo(expectedIntent) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOnePendingIntentInput { assertThat(it.pendingIntent).isEqualTo(expectedIntent) } } } packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt +49 −17 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.systemui.qs.tiles.base.actions import android.app.PendingIntent import android.content.Intent import android.content.pm.PackageManager import android.os.UserHandle import android.view.View import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.animation.ActivityLaunchAnimator Loading @@ -32,13 +34,23 @@ import javax.inject.Inject interface QSTileIntentUserInputHandler { fun handle(view: View?, intent: Intent) fun handle(view: View?, pendingIntent: PendingIntent) /** @param requestLaunchingDefaultActivity used in case !pendingIndent.isActivity */ fun handle( view: View?, pendingIntent: PendingIntent, requestLaunchingDefaultActivity: Boolean = false ) } @SysUISingleton class QSTileIntentUserInputHandlerImpl @Inject constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInputHandler { constructor( private val activityStarter: ActivityStarter, private val packageManager: PackageManager, private val userHandle: UserHandle, ) : QSTileIntentUserInputHandler { override fun handle(view: View?, intent: Intent) { val animationController: ActivityLaunchAnimator.Controller? = Loading @@ -52,10 +64,12 @@ constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInpu } // TODO(b/249804373): make sure to allow showing activities over the lockscreen. See b/292112939 override fun handle(view: View?, pendingIntent: PendingIntent) { if (!pendingIntent.isActivity) { return } override fun handle( view: View?, pendingIntent: PendingIntent, requestLaunchingDefaultActivity: Boolean ) { if (pendingIntent.isActivity) { val animationController: ActivityLaunchAnimator.Controller? = view?.let { ActivityLaunchAnimator.Controller.fromView( Loading @@ -63,10 +77,28 @@ constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInpu InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE, ) } activityStarter.startPendingIntentMaybeDismissingKeyguard( pendingIntent, null, animationController activityStarter.postStartActivityDismissingKeyguard(pendingIntent, animationController) } else if (requestLaunchingDefaultActivity) { val intent = Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) .setPackage(pendingIntent.creatorPackage) .addFlags( Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED ) val intents = packageManager.queryIntentActivitiesAsUser( intent, PackageManager.ResolveInfoFlags.of(0L), userHandle.identifier ) intents .firstOrNull { it.activityInfo.exported } ?.let { resolved -> intent.setPackage(null) intent.setComponent(resolved.activityInfo.componentName) handle(view, intent) } } } } packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt +4 −20 Original line number Diff line number Diff line Loading @@ -18,9 +18,7 @@ package com.android.systemui.qs.tiles.impl.alarm.domain.interactor import android.content.Intent import android.provider.AlarmClock import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel Loading @@ -31,34 +29,20 @@ import javax.inject.Inject class AlarmTileUserActionInteractor @Inject constructor( private val activityStarter: ActivityStarter, private val inputHandler: QSTileIntentUserInputHandler, ) : QSTileUserActionInteractor<AlarmTileModel> { override suspend fun handleInput(input: QSTileInput<AlarmTileModel>): Unit = with(input) { when (action) { is QSTileUserAction.Click -> { val animationController = action.view?.let { ActivityLaunchAnimator.Controller.fromView( it, InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE ) } if ( data is AlarmTileModel.NextAlarmSet && data.alarmClockInfo.showIntent != null ) { val pendingIndent = data.alarmClockInfo.showIntent activityStarter.postStartActivityDismissingKeyguard( pendingIndent, animationController ) inputHandler.handle(action.view, pendingIndent, true) } else { activityStarter.postStartActivityDismissingKeyguard( Intent(AlarmClock.ACTION_SHOW_ALARMS), 0, animationController ) inputHandler.handle(action.view, Intent(AlarmClock.ACTION_SHOW_ALARMS)) } } is QSTileUserAction.LongClick -> {} Loading packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt +11 −4 Original line number Diff line number Diff line Loading @@ -35,14 +35,21 @@ class FakeQSTileIntentUserInputHandler : QSTileIntentUserInputHandler { mutableInputs.add(Input.Intent(view, intent)) } override fun handle(view: View?, pendingIntent: PendingIntent) { mutableInputs.add(Input.PendingIntent(view, pendingIntent)) override fun handle( view: View?, pendingIntent: PendingIntent, requestLaunchingDefaultActivity: Boolean ) { mutableInputs.add(Input.PendingIntent(view, pendingIntent, requestLaunchingDefaultActivity)) } 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 data class PendingIntent( val view: View?, val pendingIntent: android.app.PendingIntent, val requestLaunchingDefaultActivity: Boolean ) : Input } } Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt +114 −4 Original line number Diff line number Diff line Loading @@ -16,32 +16,45 @@ package com.android.systemui.qs.tiles.base.actions import android.app.PendingIntent import android.content.ComponentName import android.content.Intent import android.content.pm.ActivityInfo import android.content.pm.PackageManager import android.content.pm.PackageManager.ResolveInfoFlags import android.content.pm.ResolveInfo import android.os.UserHandle import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.plugins.ActivityStarter import com.android.systemui.util.mockito.argThat import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatcher import org.mockito.Mock import org.mockito.Mockito.any import org.mockito.Mockito.eq import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) class QSTileIntentUserInputHandlerTest : SysuiTestCase() { @Mock private lateinit var activityStarted: ActivityStarter @Mock private lateinit var packageManager: PackageManager @Mock private lateinit var activityStarter: ActivityStarter lateinit var underTest: QSTileIntentUserInputHandler @Before fun setup() { MockitoAnnotations.initMocks(this) underTest = QSTileIntentUserInputHandlerImpl(activityStarted) underTest = QSTileIntentUserInputHandlerImpl(activityStarter, packageManager, user) } @Test Loading @@ -50,6 +63,103 @@ class QSTileIntentUserInputHandlerTest : SysuiTestCase() { underTest.handle(null, intent) verify(activityStarted).postStartActivityDismissingKeyguard(eq(intent), eq(0), any()) verify(activityStarter).postStartActivityDismissingKeyguard(eq(intent), eq(0), any()) } @Test fun testPassesActivityPendingIntentToStarterAsPendingIntent() { val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } underTest.handle(null, pendingIntent, true) verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any()) } @Test fun testPassesActivityPendingIntentToStarterAsPendingIntentWhenNotRequestingActivityStart() { val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } underTest.handle(null, pendingIntent, false) verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any()) } @Test fun testPassNonActivityPendingIntentAndRequestStartingActivity_findsIntentAndStarts() { val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(false) whenever(creatorPackage).thenReturn(ORIGINAL_PACKAGE) } setUpQueryResult(listOf(createActivityInfo(testResolvedComponent, exported = true))) underTest.handle(null, pendingIntent, true) val expectedIntent = Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) .setPackage(null) .addFlags( Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED ) .setComponent(testResolvedComponent) verify(activityStarter) .postStartActivityDismissingKeyguard( argThat(IntentMatcher(expectedIntent)), eq(0), any() ) } @Test fun testPassNonActivityPendingIntentAndDoNotRequestStartingActivity_doesNotStartActivity() { val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(false) } underTest.handle(null, pendingIntent, false) verify(activityStarter, never()) .postStartActivityDismissingKeyguard(any(Intent::class.java), eq(0), any()) } private fun createActivityInfo( componentName: ComponentName, exported: Boolean = false, ): ActivityInfo { return ActivityInfo().apply { packageName = componentName.packageName name = componentName.className this.exported = exported } } private fun setUpQueryResult(infos: List<ActivityInfo>) { `when`( packageManager.queryIntentActivitiesAsUser( any(Intent::class.java), any(ResolveInfoFlags::class.java), eq(user.identifier) ) ) .thenReturn(infos.map { ResolveInfo().apply { activityInfo = it } }) } private class IntentMatcher(intent: Intent) : ArgumentMatcher<Intent> { private val expectedIntent = intent override fun matches(argument: Intent?): Boolean { return argument?.action.equals(expectedIntent.action) && argument?.`package`.equals(expectedIntent.`package`) && argument?.component?.equals(expectedIntent.component)!! && argument?.categories?.equals(expectedIntent.categories)!! && argument?.flags?.equals(expectedIntent.flags)!! } } companion object { private const val ORIGINAL_PACKAGE = "original_pkg" private const val TEST_PACKAGE = "test_pkg" private const val TEST_COMPONENT_CLASS_NAME = "test_component_class_name" private val testResolvedComponent = ComponentName(TEST_PACKAGE, TEST_COMPONENT_CLASS_NAME) private val user = UserHandle.of(0) } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt +11 −28 Original line number Diff line number Diff line Loading @@ -18,42 +18,25 @@ package com.android.systemui.qs.tiles.impl.alarm.domain.interactor import android.app.AlarmManager.AlarmClockInfo import android.app.PendingIntent import android.content.Intent import android.provider.AlarmClock import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx.click import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mockito.verify @SmallTest @RunWith(AndroidJUnit4::class) class AlarmTileUserActionInteractorTest : SysuiTestCase() { private lateinit var activityStarter: ActivityStarter private lateinit var intentCaptor: ArgumentCaptor<Intent> private lateinit var pendingIntentCaptor: ArgumentCaptor<PendingIntent> lateinit var underTest: AlarmTileUserActionInteractor @Before fun setup() { activityStarter = mock<ActivityStarter>() intentCaptor = ArgumentCaptor.forClass(Intent::class.java) pendingIntentCaptor = ArgumentCaptor.forClass(PendingIntent::class.java) underTest = AlarmTileUserActionInteractor(activityStarter) } private val inputHandler = FakeQSTileIntentUserInputHandler() private val underTest = AlarmTileUserActionInteractor(inputHandler) @Test fun handleClickWithDefaultIntent() = runTest { Loading @@ -62,21 +45,21 @@ class AlarmTileUserActionInteractorTest : SysuiTestCase() { underTest.handleInput(click(inputModel)) verify(activityStarter) .postStartActivityDismissingKeyguard(capture(intentCaptor), eq(0), nullable()) assertThat(intentCaptor.value.action).isEqualTo(AlarmClock.ACTION_SHOW_ALARMS) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { assertThat(it.intent.action).isEqualTo(AlarmClock.ACTION_SHOW_ALARMS) } } @Test fun handleClickWithPendingIntent() = runTest { val expectedIntent: PendingIntent = mock<PendingIntent>() val expectedIntent = mock<PendingIntent>() val alarmInfo = AlarmClockInfo(1L, expectedIntent) val inputModel = AlarmTileModel.NextAlarmSet(true, alarmInfo) underTest.handleInput(click(inputModel)) verify(activityStarter) .postStartActivityDismissingKeyguard(capture(pendingIntentCaptor), nullable()) assertThat(pendingIntentCaptor.value).isEqualTo(expectedIntent) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOnePendingIntentInput { assertThat(it.pendingIntent).isEqualTo(expectedIntent) } } }
packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt +49 −17 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.systemui.qs.tiles.base.actions import android.app.PendingIntent import android.content.Intent import android.content.pm.PackageManager import android.os.UserHandle import android.view.View import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.animation.ActivityLaunchAnimator Loading @@ -32,13 +34,23 @@ import javax.inject.Inject interface QSTileIntentUserInputHandler { fun handle(view: View?, intent: Intent) fun handle(view: View?, pendingIntent: PendingIntent) /** @param requestLaunchingDefaultActivity used in case !pendingIndent.isActivity */ fun handle( view: View?, pendingIntent: PendingIntent, requestLaunchingDefaultActivity: Boolean = false ) } @SysUISingleton class QSTileIntentUserInputHandlerImpl @Inject constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInputHandler { constructor( private val activityStarter: ActivityStarter, private val packageManager: PackageManager, private val userHandle: UserHandle, ) : QSTileIntentUserInputHandler { override fun handle(view: View?, intent: Intent) { val animationController: ActivityLaunchAnimator.Controller? = Loading @@ -52,10 +64,12 @@ constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInpu } // TODO(b/249804373): make sure to allow showing activities over the lockscreen. See b/292112939 override fun handle(view: View?, pendingIntent: PendingIntent) { if (!pendingIntent.isActivity) { return } override fun handle( view: View?, pendingIntent: PendingIntent, requestLaunchingDefaultActivity: Boolean ) { if (pendingIntent.isActivity) { val animationController: ActivityLaunchAnimator.Controller? = view?.let { ActivityLaunchAnimator.Controller.fromView( Loading @@ -63,10 +77,28 @@ constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInpu InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE, ) } activityStarter.startPendingIntentMaybeDismissingKeyguard( pendingIntent, null, animationController activityStarter.postStartActivityDismissingKeyguard(pendingIntent, animationController) } else if (requestLaunchingDefaultActivity) { val intent = Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) .setPackage(pendingIntent.creatorPackage) .addFlags( Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED ) val intents = packageManager.queryIntentActivitiesAsUser( intent, PackageManager.ResolveInfoFlags.of(0L), userHandle.identifier ) intents .firstOrNull { it.activityInfo.exported } ?.let { resolved -> intent.setPackage(null) intent.setComponent(resolved.activityInfo.componentName) handle(view, intent) } } } }
packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt +4 −20 Original line number Diff line number Diff line Loading @@ -18,9 +18,7 @@ package com.android.systemui.qs.tiles.impl.alarm.domain.interactor import android.content.Intent import android.provider.AlarmClock import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel Loading @@ -31,34 +29,20 @@ import javax.inject.Inject class AlarmTileUserActionInteractor @Inject constructor( private val activityStarter: ActivityStarter, private val inputHandler: QSTileIntentUserInputHandler, ) : QSTileUserActionInteractor<AlarmTileModel> { override suspend fun handleInput(input: QSTileInput<AlarmTileModel>): Unit = with(input) { when (action) { is QSTileUserAction.Click -> { val animationController = action.view?.let { ActivityLaunchAnimator.Controller.fromView( it, InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE ) } if ( data is AlarmTileModel.NextAlarmSet && data.alarmClockInfo.showIntent != null ) { val pendingIndent = data.alarmClockInfo.showIntent activityStarter.postStartActivityDismissingKeyguard( pendingIndent, animationController ) inputHandler.handle(action.view, pendingIndent, true) } else { activityStarter.postStartActivityDismissingKeyguard( Intent(AlarmClock.ACTION_SHOW_ALARMS), 0, animationController ) inputHandler.handle(action.view, Intent(AlarmClock.ACTION_SHOW_ALARMS)) } } is QSTileUserAction.LongClick -> {} Loading
packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt +11 −4 Original line number Diff line number Diff line Loading @@ -35,14 +35,21 @@ class FakeQSTileIntentUserInputHandler : QSTileIntentUserInputHandler { mutableInputs.add(Input.Intent(view, intent)) } override fun handle(view: View?, pendingIntent: PendingIntent) { mutableInputs.add(Input.PendingIntent(view, pendingIntent)) override fun handle( view: View?, pendingIntent: PendingIntent, requestLaunchingDefaultActivity: Boolean ) { mutableInputs.add(Input.PendingIntent(view, pendingIntent, requestLaunchingDefaultActivity)) } 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 data class PendingIntent( val view: View?, val pendingIntent: android.app.PendingIntent, val requestLaunchingDefaultActivity: Boolean ) : Input } } Loading