Loading packages/SystemUI/multivalentTests/src/com/android/systemui/ambientcue/data/repository/AmbientCueRepositoryTest.kt +49 −0 Original line number Diff line number Diff line Loading @@ -28,10 +28,13 @@ import android.content.Intent import android.content.testableContext import android.os.Binder import android.os.Bundle import android.view.WindowManagerPolicyConstants import android.view.autofill.AutofillId import android.view.autofill.AutofillManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.LauncherProxyService import com.android.systemui.LauncherProxyService.LauncherProxyListener import com.android.systemui.SysuiTestCase import com.android.systemui.ambientcue.data.repository.AmbientCueRepositoryImpl.Companion.AMBIENT_CUE_SURFACE import com.android.systemui.ambientcue.data.repository.AmbientCueRepositoryImpl.Companion.DEBOUNCE_DELAY_MS Loading @@ -45,6 +48,8 @@ import com.android.systemui.kosmos.backgroundScope import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest import com.android.systemui.navigationbar.NavigationModeController import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener import com.android.systemui.plugins.ActivityStarter import com.android.systemui.shade.data.repository.fakeFocusedDisplayRepository import com.android.systemui.testKosmos Loading @@ -65,17 +70,23 @@ class AmbientCueRepositoryTest : SysuiTestCase() { private val smartSpaceSession = mock<SmartspaceSession>() private val autofillManager = mock<AutofillManager>() private val activityStarter = mock<ActivityStarter>() private val launcherProxyService = mock<LauncherProxyService>() private val navigationModeController = mock<NavigationModeController>() private val smartSpaceManager = mock<SmartspaceManager>() { on { createSmartspaceSession(any()) } doReturn smartSpaceSession } val onTargetsAvailableListenerCaptor = argumentCaptor<OnTargetsAvailableListener>() val navigationModeChangeListenerCaptor = argumentCaptor<ModeChangedListener>() val launcherProxyListenerCaptor = argumentCaptor<LauncherProxyListener>() private val underTest = AmbientCueRepositoryImpl( backgroundScope = kosmos.backgroundScope, smartSpaceManager = smartSpaceManager, autofillManager = autofillManager, activityStarter = activityStarter, launcherProxyService = launcherProxyService, navigationModeController = navigationModeController, executor = kosmos.fakeExecutor, applicationContext = kosmos.testableContext, focusdDisplayRepository = kosmos.fakeFocusedDisplayRepository, Loading Loading @@ -251,6 +262,44 @@ class AmbientCueRepositoryTest : SysuiTestCase() { assertThat(targetTaskId).isEqualTo(TASK_ID) } fun isGestureNav_propagatesFromNavigationModeController() = kosmos.runTest { val isGestureNav by collectLastValue(underTest.isGestureNav) runCurrent() verify(navigationModeController) .addListener(navigationModeChangeListenerCaptor.capture()) navigationModeChangeListenerCaptor.firstValue.onNavigationModeChanged( WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL ) assertThat(isGestureNav).isTrue() navigationModeChangeListenerCaptor.firstValue.onNavigationModeChanged( WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON ) assertThat(isGestureNav).isFalse() } @Test fun isTaskBarVisible_propagatesFromLauncherProxyService() = kosmos.runTest { val isTaskBarVisible by collectLastValue(underTest.isTaskBarVisible) runCurrent() verify(launcherProxyService).addCallback(launcherProxyListenerCaptor.capture()) launcherProxyListenerCaptor.firstValue.onTaskbarStatusUpdated(false, false) runCurrent() assertThat(isTaskBarVisible).isFalse() launcherProxyListenerCaptor.firstValue.onTaskbarStatusUpdated(true, false) runCurrent() assertThat(isTaskBarVisible).isTrue() launcherProxyListenerCaptor.firstValue.onTaskbarStatusUpdated(true, true) runCurrent() assertThat(isTaskBarVisible).isFalse() } companion object { private const val TITLE_1 = "title 1" Loading packages/SystemUI/src/com/android/systemui/ambientcue/data/repository/AmbientCueRepository.kt +41 −0 Original line number Diff line number Diff line Loading @@ -26,13 +26,17 @@ import android.util.Log import android.view.autofill.AutofillId import android.view.autofill.AutofillManager import androidx.annotation.VisibleForTesting import com.android.systemui.LauncherProxyService import com.android.systemui.LauncherProxyService.LauncherProxyListener import com.android.systemui.ambientcue.shared.model.ActionModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.display.data.repository.FocusedDisplayRepository import com.android.systemui.navigationbar.NavigationModeController import com.android.systemui.plugins.ActivityStarter import com.android.systemui.res.R import com.android.systemui.shared.system.QuickStepContract import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import java.util.concurrent.Executor import javax.inject.Inject Loading Loading @@ -66,6 +70,12 @@ interface AmbientCueRepository { /** If the UI is deactivated, such as closed by user or not used for a long period. */ val isDeactivated: MutableStateFlow<Boolean> /** If the taskbar is fully visible and not stashed. */ val isTaskBarVisible: StateFlow<Boolean> /** True if in gesture nav mode, false when in 3-button navbar. */ val isGestureNav: StateFlow<Boolean> } @SysUISingleton Loading @@ -76,6 +86,8 @@ constructor( private val smartSpaceManager: SmartspaceManager?, private val autofillManager: AutofillManager?, private val activityStarter: ActivityStarter, private val launcherProxyService: LauncherProxyService, private val navigationModeController: NavigationModeController, @Background executor: Executor, @Application applicationContext: Context, focusdDisplayRepository: FocusedDisplayRepository, Loading Loading @@ -171,6 +183,35 @@ constructor( initialValue = emptyList(), ) override val isTaskBarVisible: StateFlow<Boolean> = conflatedCallbackFlow { val callback = object : LauncherProxyListener { override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) { trySend(visible && !stashed) } } launcherProxyService.addCallback(callback) awaitClose { launcherProxyService.removeCallback(callback) } } .stateIn( scope = backgroundScope, started = SharingStarted.WhileSubscribed(), initialValue = false, ) override val isGestureNav: StateFlow<Boolean> = conflatedCallbackFlow { val listener = NavigationModeController.ModeChangedListener { mode -> trySend(QuickStepContract.isGesturalMode(mode)) } val navBarMode = navigationModeController.addListener(listener) listener.onNavigationModeChanged(navBarMode) awaitClose { navigationModeController.removeListener(listener) } } .stateIn(backgroundScope, SharingStarted.WhileSubscribed(), false) override val isImeVisible: MutableStateFlow<Boolean> = MutableStateFlow(false) override val isDeactivated: MutableStateFlow<Boolean> = MutableStateFlow(false) Loading packages/SystemUI/tests/utils/src/com/android/systemui/ambientcue/data/repository/FakeAmbientCueRepository.kt +14 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,12 @@ class FakeAmbientCueRepository : AmbientCueRepository { private val targetTaskId: MutableStateFlow<Int> = MutableStateFlow(0) override val isDeactivated: MutableStateFlow<Boolean> = MutableStateFlow(false) private val _isTaskBarVisible = MutableStateFlow(false) override val isTaskBarVisible: StateFlow<Boolean> = _isTaskBarVisible.asStateFlow() private val _isGestureNav = MutableStateFlow(false) override val isGestureNav: StateFlow<Boolean> = _isGestureNav.asStateFlow() fun setActions(actions: List<ActionModel>) { _actions.update { actions } } Loading @@ -55,4 +61,12 @@ class FakeAmbientCueRepository : AmbientCueRepository { targetTaskId.value == globallyFocusedTaskId.value } } fun setTaskBarVisible(visible: Boolean) { _isTaskBarVisible.update { visible } } fun setIsGestureNav(isGestureNav: Boolean) { _isGestureNav.update { isGestureNav } } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/ambientcue/data/repository/AmbientCueRepositoryTest.kt +49 −0 Original line number Diff line number Diff line Loading @@ -28,10 +28,13 @@ import android.content.Intent import android.content.testableContext import android.os.Binder import android.os.Bundle import android.view.WindowManagerPolicyConstants import android.view.autofill.AutofillId import android.view.autofill.AutofillManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.LauncherProxyService import com.android.systemui.LauncherProxyService.LauncherProxyListener import com.android.systemui.SysuiTestCase import com.android.systemui.ambientcue.data.repository.AmbientCueRepositoryImpl.Companion.AMBIENT_CUE_SURFACE import com.android.systemui.ambientcue.data.repository.AmbientCueRepositoryImpl.Companion.DEBOUNCE_DELAY_MS Loading @@ -45,6 +48,8 @@ import com.android.systemui.kosmos.backgroundScope import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest import com.android.systemui.navigationbar.NavigationModeController import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener import com.android.systemui.plugins.ActivityStarter import com.android.systemui.shade.data.repository.fakeFocusedDisplayRepository import com.android.systemui.testKosmos Loading @@ -65,17 +70,23 @@ class AmbientCueRepositoryTest : SysuiTestCase() { private val smartSpaceSession = mock<SmartspaceSession>() private val autofillManager = mock<AutofillManager>() private val activityStarter = mock<ActivityStarter>() private val launcherProxyService = mock<LauncherProxyService>() private val navigationModeController = mock<NavigationModeController>() private val smartSpaceManager = mock<SmartspaceManager>() { on { createSmartspaceSession(any()) } doReturn smartSpaceSession } val onTargetsAvailableListenerCaptor = argumentCaptor<OnTargetsAvailableListener>() val navigationModeChangeListenerCaptor = argumentCaptor<ModeChangedListener>() val launcherProxyListenerCaptor = argumentCaptor<LauncherProxyListener>() private val underTest = AmbientCueRepositoryImpl( backgroundScope = kosmos.backgroundScope, smartSpaceManager = smartSpaceManager, autofillManager = autofillManager, activityStarter = activityStarter, launcherProxyService = launcherProxyService, navigationModeController = navigationModeController, executor = kosmos.fakeExecutor, applicationContext = kosmos.testableContext, focusdDisplayRepository = kosmos.fakeFocusedDisplayRepository, Loading Loading @@ -251,6 +262,44 @@ class AmbientCueRepositoryTest : SysuiTestCase() { assertThat(targetTaskId).isEqualTo(TASK_ID) } fun isGestureNav_propagatesFromNavigationModeController() = kosmos.runTest { val isGestureNav by collectLastValue(underTest.isGestureNav) runCurrent() verify(navigationModeController) .addListener(navigationModeChangeListenerCaptor.capture()) navigationModeChangeListenerCaptor.firstValue.onNavigationModeChanged( WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL ) assertThat(isGestureNav).isTrue() navigationModeChangeListenerCaptor.firstValue.onNavigationModeChanged( WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON ) assertThat(isGestureNav).isFalse() } @Test fun isTaskBarVisible_propagatesFromLauncherProxyService() = kosmos.runTest { val isTaskBarVisible by collectLastValue(underTest.isTaskBarVisible) runCurrent() verify(launcherProxyService).addCallback(launcherProxyListenerCaptor.capture()) launcherProxyListenerCaptor.firstValue.onTaskbarStatusUpdated(false, false) runCurrent() assertThat(isTaskBarVisible).isFalse() launcherProxyListenerCaptor.firstValue.onTaskbarStatusUpdated(true, false) runCurrent() assertThat(isTaskBarVisible).isTrue() launcherProxyListenerCaptor.firstValue.onTaskbarStatusUpdated(true, true) runCurrent() assertThat(isTaskBarVisible).isFalse() } companion object { private const val TITLE_1 = "title 1" Loading
packages/SystemUI/src/com/android/systemui/ambientcue/data/repository/AmbientCueRepository.kt +41 −0 Original line number Diff line number Diff line Loading @@ -26,13 +26,17 @@ import android.util.Log import android.view.autofill.AutofillId import android.view.autofill.AutofillManager import androidx.annotation.VisibleForTesting import com.android.systemui.LauncherProxyService import com.android.systemui.LauncherProxyService.LauncherProxyListener import com.android.systemui.ambientcue.shared.model.ActionModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.display.data.repository.FocusedDisplayRepository import com.android.systemui.navigationbar.NavigationModeController import com.android.systemui.plugins.ActivityStarter import com.android.systemui.res.R import com.android.systemui.shared.system.QuickStepContract import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import java.util.concurrent.Executor import javax.inject.Inject Loading Loading @@ -66,6 +70,12 @@ interface AmbientCueRepository { /** If the UI is deactivated, such as closed by user or not used for a long period. */ val isDeactivated: MutableStateFlow<Boolean> /** If the taskbar is fully visible and not stashed. */ val isTaskBarVisible: StateFlow<Boolean> /** True if in gesture nav mode, false when in 3-button navbar. */ val isGestureNav: StateFlow<Boolean> } @SysUISingleton Loading @@ -76,6 +86,8 @@ constructor( private val smartSpaceManager: SmartspaceManager?, private val autofillManager: AutofillManager?, private val activityStarter: ActivityStarter, private val launcherProxyService: LauncherProxyService, private val navigationModeController: NavigationModeController, @Background executor: Executor, @Application applicationContext: Context, focusdDisplayRepository: FocusedDisplayRepository, Loading Loading @@ -171,6 +183,35 @@ constructor( initialValue = emptyList(), ) override val isTaskBarVisible: StateFlow<Boolean> = conflatedCallbackFlow { val callback = object : LauncherProxyListener { override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) { trySend(visible && !stashed) } } launcherProxyService.addCallback(callback) awaitClose { launcherProxyService.removeCallback(callback) } } .stateIn( scope = backgroundScope, started = SharingStarted.WhileSubscribed(), initialValue = false, ) override val isGestureNav: StateFlow<Boolean> = conflatedCallbackFlow { val listener = NavigationModeController.ModeChangedListener { mode -> trySend(QuickStepContract.isGesturalMode(mode)) } val navBarMode = navigationModeController.addListener(listener) listener.onNavigationModeChanged(navBarMode) awaitClose { navigationModeController.removeListener(listener) } } .stateIn(backgroundScope, SharingStarted.WhileSubscribed(), false) override val isImeVisible: MutableStateFlow<Boolean> = MutableStateFlow(false) override val isDeactivated: MutableStateFlow<Boolean> = MutableStateFlow(false) Loading
packages/SystemUI/tests/utils/src/com/android/systemui/ambientcue/data/repository/FakeAmbientCueRepository.kt +14 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,12 @@ class FakeAmbientCueRepository : AmbientCueRepository { private val targetTaskId: MutableStateFlow<Int> = MutableStateFlow(0) override val isDeactivated: MutableStateFlow<Boolean> = MutableStateFlow(false) private val _isTaskBarVisible = MutableStateFlow(false) override val isTaskBarVisible: StateFlow<Boolean> = _isTaskBarVisible.asStateFlow() private val _isGestureNav = MutableStateFlow(false) override val isGestureNav: StateFlow<Boolean> = _isGestureNav.asStateFlow() fun setActions(actions: List<ActionModel>) { _actions.update { actions } } Loading @@ -55,4 +61,12 @@ class FakeAmbientCueRepository : AmbientCueRepository { targetTaskId.value == globallyFocusedTaskId.value } } fun setTaskBarVisible(visible: Boolean) { _isTaskBarVisible.update { visible } } fun setIsGestureNav(isGestureNav: Boolean) { _isGestureNav.update { isGestureNav } } }