Loading packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorTest.kt +25 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.communal.domain.interactor import android.app.ActivityManager.RunningTaskInfo import android.app.usage.UsageEvents import android.content.pm.UserInfo import android.service.dream.dreamManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase Loading @@ -28,6 +29,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.ActivityStarter.OnDismissAction import com.android.systemui.plugins.activityStarter import com.android.systemui.settings.fakeUserTracker import com.android.systemui.shared.system.taskStackChangeListeners Loading @@ -48,6 +50,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.times Loading Loading @@ -89,6 +92,27 @@ class WidgetTrampolineInteractorTest : SysuiTestCase() { verify(activityStarter).dismissKeyguardThenExecute(any(), anyOrNull(), any()) } @Test fun testNewTaskStartsWhileOnHub_stopsDream() = testScope.runTest { transition(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GLANCEABLE_HUB) backgroundScope.launch { underTest.waitForActivityStartAndDismissKeyguard() } runCurrent() verify(activityStarter, never()).dismissKeyguardThenExecute(any(), anyOrNull(), any()) moveTaskToFront() argumentCaptor<OnDismissAction>().apply { verify(activityStarter).dismissKeyguardThenExecute(capture(), anyOrNull(), any()) firstValue.onDismiss() runCurrent() // Dream is stopped once keyguard is dismissed. verify(kosmos.dreamManager).stopDream() } } @Test fun testNewTaskStartsAfterExitingHub_doesNotTriggerUnlock() = testScope.runTest { Loading Loading @@ -209,7 +233,7 @@ class WidgetTrampolineInteractorTest : SysuiTestCase() { ownerName = "test", ), ), testScope testScope, ) runCurrent() } Loading packages/SystemUI/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractor.kt +17 −2 Original line number Diff line number Diff line Loading @@ -16,10 +16,13 @@ package com.android.systemui.communal.domain.interactor import android.annotation.SuppressLint import android.app.ActivityManager import android.app.DreamManager import com.android.systemui.common.usagestats.domain.UsageStatsInteractor import com.android.systemui.common.usagestats.shared.model.ActivityEventModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.log.LogBuffer Loading @@ -34,10 +37,12 @@ import com.android.systemui.util.time.SystemClock import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.delay import kotlinx.coroutines.flow.takeWhile import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withTimeout Loading @@ -56,6 +61,8 @@ constructor( private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val taskStackChangeListeners: TaskStackChangeListeners, private val usageStatsInteractor: UsageStatsInteractor, private val dreamManager: DreamManager, @Background private val bgScope: CoroutineScope, @CommunalLog logBuffer: LogBuffer, ) { private companion object { Loading Loading @@ -127,13 +134,21 @@ constructor( * Checks if an activity starts while on the glanceable hub and dismisses the keyguard if it * does. This can detect activities started due to broadcast trampolines from widgets. */ @SuppressLint("MissingPermission") suspend fun waitForActivityStartAndDismissKeyguard() { if (waitForActivityStartWhileOnHub()) { logger.d("Detected trampoline, requesting unlock") activityStarter.dismissKeyguardThenExecute( /* action= */ { false }, /* action= */ { // Kill the dream when launching the trampoline activity. Right now the exit // animation stalls when tapping the battery widget, and the dream remains // visible until the transition hits some timeouts and gets cancelled. // TODO(b/362841648): remove once exit animation is fixed. bgScope.launch { dreamManager.stopDream() } false }, /* cancel= */ null, /* afterKeyguardGone= */ false /* afterKeyguardGone= */ false, ) } } Loading packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorKosmos.kt +4 −0 Original line number Diff line number Diff line Loading @@ -16,9 +16,11 @@ package com.android.systemui.communal.domain.interactor import android.service.dream.dreamManager import com.android.systemui.common.usagestats.domain.interactor.usageStatsInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.plugins.activityStarter import com.android.systemui.shared.system.taskStackChangeListeners Loading @@ -32,6 +34,8 @@ val Kosmos.widgetTrampolineInteractor: WidgetTrampolineInteractor by keyguardTransitionInteractor = keyguardTransitionInteractor, taskStackChangeListeners = taskStackChangeListeners, usageStatsInteractor = usageStatsInteractor, dreamManager = dreamManager, bgScope = applicationCoroutineScope, logBuffer = logcatLogBuffer("WidgetTrampolineInteractor"), ) } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorTest.kt +25 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.communal.domain.interactor import android.app.ActivityManager.RunningTaskInfo import android.app.usage.UsageEvents import android.content.pm.UserInfo import android.service.dream.dreamManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase Loading @@ -28,6 +29,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.ActivityStarter.OnDismissAction import com.android.systemui.plugins.activityStarter import com.android.systemui.settings.fakeUserTracker import com.android.systemui.shared.system.taskStackChangeListeners Loading @@ -48,6 +50,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.times Loading Loading @@ -89,6 +92,27 @@ class WidgetTrampolineInteractorTest : SysuiTestCase() { verify(activityStarter).dismissKeyguardThenExecute(any(), anyOrNull(), any()) } @Test fun testNewTaskStartsWhileOnHub_stopsDream() = testScope.runTest { transition(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GLANCEABLE_HUB) backgroundScope.launch { underTest.waitForActivityStartAndDismissKeyguard() } runCurrent() verify(activityStarter, never()).dismissKeyguardThenExecute(any(), anyOrNull(), any()) moveTaskToFront() argumentCaptor<OnDismissAction>().apply { verify(activityStarter).dismissKeyguardThenExecute(capture(), anyOrNull(), any()) firstValue.onDismiss() runCurrent() // Dream is stopped once keyguard is dismissed. verify(kosmos.dreamManager).stopDream() } } @Test fun testNewTaskStartsAfterExitingHub_doesNotTriggerUnlock() = testScope.runTest { Loading Loading @@ -209,7 +233,7 @@ class WidgetTrampolineInteractorTest : SysuiTestCase() { ownerName = "test", ), ), testScope testScope, ) runCurrent() } Loading
packages/SystemUI/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractor.kt +17 −2 Original line number Diff line number Diff line Loading @@ -16,10 +16,13 @@ package com.android.systemui.communal.domain.interactor import android.annotation.SuppressLint import android.app.ActivityManager import android.app.DreamManager import com.android.systemui.common.usagestats.domain.UsageStatsInteractor import com.android.systemui.common.usagestats.shared.model.ActivityEventModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.log.LogBuffer Loading @@ -34,10 +37,12 @@ import com.android.systemui.util.time.SystemClock import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.delay import kotlinx.coroutines.flow.takeWhile import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withTimeout Loading @@ -56,6 +61,8 @@ constructor( private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val taskStackChangeListeners: TaskStackChangeListeners, private val usageStatsInteractor: UsageStatsInteractor, private val dreamManager: DreamManager, @Background private val bgScope: CoroutineScope, @CommunalLog logBuffer: LogBuffer, ) { private companion object { Loading Loading @@ -127,13 +134,21 @@ constructor( * Checks if an activity starts while on the glanceable hub and dismisses the keyguard if it * does. This can detect activities started due to broadcast trampolines from widgets. */ @SuppressLint("MissingPermission") suspend fun waitForActivityStartAndDismissKeyguard() { if (waitForActivityStartWhileOnHub()) { logger.d("Detected trampoline, requesting unlock") activityStarter.dismissKeyguardThenExecute( /* action= */ { false }, /* action= */ { // Kill the dream when launching the trampoline activity. Right now the exit // animation stalls when tapping the battery widget, and the dream remains // visible until the transition hits some timeouts and gets cancelled. // TODO(b/362841648): remove once exit animation is fixed. bgScope.launch { dreamManager.stopDream() } false }, /* cancel= */ null, /* afterKeyguardGone= */ false /* afterKeyguardGone= */ false, ) } } Loading
packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/WidgetTrampolineInteractorKosmos.kt +4 −0 Original line number Diff line number Diff line Loading @@ -16,9 +16,11 @@ package com.android.systemui.communal.domain.interactor import android.service.dream.dreamManager import com.android.systemui.common.usagestats.domain.interactor.usageStatsInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.plugins.activityStarter import com.android.systemui.shared.system.taskStackChangeListeners Loading @@ -32,6 +34,8 @@ val Kosmos.widgetTrampolineInteractor: WidgetTrampolineInteractor by keyguardTransitionInteractor = keyguardTransitionInteractor, taskStackChangeListeners = taskStackChangeListeners, usageStatsInteractor = usageStatsInteractor, dreamManager = dreamManager, bgScope = applicationCoroutineScope, logBuffer = logcatLogBuffer("WidgetTrampolineInteractor"), ) }