Loading packages/SystemUI/aconfig/systemui.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -453,6 +453,16 @@ flag { } } flag { name: "status_bar_always_schedule_auto_hide" namespace: "systemui" description: "Schedule the status bar auto-hide functionality more often for fullscreen mode" bug: "428659575" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "status_bar_app_handle_tracking" namespace: "systemui" Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt +137 −1 Original line number Diff line number Diff line Loading @@ -16,13 +16,16 @@ package com.android.systemui.statusbar.core import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.View import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository import com.android.systemui.dump.dumpManager import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.plugins.DarkIconDispatcher Loading @@ -36,8 +39,11 @@ import com.android.systemui.statusbar.data.model.StatusBarMode import com.android.systemui.statusbar.data.model.StatusBarMode.LIGHTS_OUT import com.android.systemui.statusbar.data.model.StatusBarMode.LIGHTS_OUT_TRANSPARENT import com.android.systemui.statusbar.data.model.StatusBarMode.OPAQUE import com.android.systemui.statusbar.data.model.StatusBarMode.SEMI_TRANSPARENT import com.android.systemui.statusbar.data.model.StatusBarMode.TRANSPARENT import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions import com.android.systemui.statusbar.phone.mockAutoHideController import com.android.systemui.statusbar.phone.ui.statusBarIconController import com.android.systemui.statusbar.policy.fakeConfigurationController import com.android.systemui.statusbar.window.data.repository.fakeStatusBarWindowStatePerDisplayRepository Loading @@ -50,7 +56,9 @@ import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.reset import org.mockito.kotlin.times import org.mockito.kotlin.verify Loading @@ -72,7 +80,6 @@ class StatusBarOrchestratorTest : SysuiTestCase() { private val fakeStatusBarWindowController = kosmos.fakeStatusBarWindowController private val fakeStatusBarInitializer = kosmos.fakeStatusBarInitializer private val dumpManager = kosmos.dumpManager private val statusBarIconRefreshInteractor = kosmos.statusBarIconRefreshInteractor private val orchestrator = kosmos.statusBarOrchestrator Loading Loading @@ -141,6 +148,135 @@ class StatusBarOrchestratorTest : SysuiTestCase() { verify(fakeStatusBarInitializer.statusBarTransitions, never()).finishAnimations() } @Test @DisableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_invokedWhenBarModeChanges_flagOff() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) setStatusBarMode(SEMI_TRANSPARENT) verify(mockAutoHideController).touchAutoHide() reset(mockAutoHideController) setStatusBarMode(OPAQUE) verify(mockAutoHideController).touchAutoHide() } @Test @EnableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_invokedWhenBarModeChanges_flagOn() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) setStatusBarMode(SEMI_TRANSPARENT) verify(mockAutoHideController).touchAutoHide() reset(mockAutoHideController) setStatusBarMode(OPAQUE) verify(mockAutoHideController).touchAutoHide() } @Test @DisableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_invokedWhenTransitionsChanges_flagOff() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) fakeStatusBarInitializer.setNewTransitions(mock<PhoneStatusBarTransitions>()) verify(mockAutoHideController).touchAutoHide() } @Test @EnableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_invokedWhenTransitionsChanges_flagOn() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) fakeStatusBarInitializer.setNewTransitions(mock<PhoneStatusBarTransitions>()) verify(mockAutoHideController).touchAutoHide() } @Test @DisableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_notInvokedWhenAnimateChanges_flagOff() = kosmos.runTest { setStatusBarMode(TRANSPARENT) setStatusBarWindowState(StatusBarWindowState.Showing) orchestrator.start() reset(mockAutoHideController) // Changing the window state will affect the `shouldAnimateNextBarModeChange` value setStatusBarWindowState(StatusBarWindowState.Hidden) verify(mockAutoHideController, never()).touchAutoHide() } @Test @EnableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_notInvokedWhenAnimateChanges_flagOn() = kosmos.runTest { setStatusBarMode(TRANSPARENT) setStatusBarWindowState(StatusBarWindowState.Showing) orchestrator.start() reset(mockAutoHideController) // Changing the window state will affect the `shouldAnimateNextBarModeChange` value setStatusBarWindowState(StatusBarWindowState.Hidden) verify(mockAutoHideController, never()).touchAutoHide() } @Test @DisableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_flagOff_notInvokedWhenTransientShownStateChanges() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) setTransientStatusBar() verify(mockAutoHideController, never()).touchAutoHide() reset(mockAutoHideController) abortTransientStatusBar() verify(mockAutoHideController, never()).touchAutoHide() } /** Regression test for b/428659575. */ @Test @EnableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_flagOn_invokedWhenTransientShownStateChanges() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) setTransientStatusBar() verify(mockAutoHideController).touchAutoHide() reset(mockAutoHideController) abortTransientStatusBar() verify(mockAutoHideController).touchAutoHide() } @Test fun statusBarVisible_notifiesBubbles() = testScope.runTest { Loading packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt +37 −14 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.view.Display import android.view.View import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.Dumpable import com.android.systemui.Flags import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.demomode.DemoModeController Loading Loading @@ -133,17 +134,33 @@ constructor( statusBarWindowState != StatusBarWindowState.Hidden } private val barModeUpdate = private data class BarModeAppearance( val animate: Boolean, val barTransitions: PhoneStatusBarTransitions, val statusBarMode: StatusBarMode, val isTransientShown: Boolean, ) private val barModeAppearance = combine( shouldAnimateNextBarModeChange, phoneStatusBarTransitions.filterNotNull(), statusBarModeRepository.statusBarMode, ::Triple, statusBarModeRepository.isTransientShown, ::BarModeAppearance, ) .distinctUntilChangedBy { (_, barTransitions, statusBarMode) -> // We only want to collect when either bar transitions or status bar mode // changed. Pair(barTransitions, statusBarMode) private val barModeUpdate = barModeAppearance.distinctUntilChangedBy { // We only want to collect when either bar transitions or status bar mode changed. Pair(it.barTransitions, it.statusBarMode) } private val autoHideUpdate = barModeAppearance.distinctUntilChangedBy { // Update auto-hide whenever `isTransientShown` changes so that we always hide the // transient status bar even if `statusBarMode` hasn't changed. See b/428659575. Triple(it.barTransitions, it.statusBarMode, it.isTransientShown) } /** Starts status bar orchestration. To be called when status bar is created. */ Loading @@ -168,9 +185,12 @@ constructor( } launch { statusBarVisible.collect { updateBubblesVisibility(it) } } launch { barModeUpdate.collect { (animate, barTransitions, statusBarMode) -> updateBarMode(animate, barTransitions, statusBarMode) barModeUpdate.collect { updateBarMode(it.animate, it.barTransitions, it.statusBarMode) } } if (Flags.statusBarAlwaysScheduleAutoHide()) { launch { autoHideUpdate.collect { autoHideController.touchAutoHide() } } } } createAndAddWindow() Loading Loading @@ -238,8 +258,11 @@ constructor( if (!demoModeController.isInDemoMode) { barTransitions.transitionTo(barMode.toTransitionModeInt(), animate) } if (!Flags.statusBarAlwaysScheduleAutoHide()) { autoHideController.touchAutoHide() } } private fun updateBubblesVisibility(statusBarVisible: Boolean) { if (displayId != Display.DEFAULT_DISPLAY) { Loading packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializer.kt +9 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ import org.mockito.kotlin.mock class FakeStatusBarInitializer : StatusBarInitializer { val statusBarViewController = mock<PhoneStatusBarViewController>() val statusBarTransitions = mock<PhoneStatusBarTransitions>() var statusBarTransitions = mock<PhoneStatusBarTransitions>() var startedByCoreStartable: Boolean = false private set Loading @@ -47,4 +47,12 @@ class FakeStatusBarInitializer : StatusBarInitializer { override fun start() { startedByCoreStartable = true } fun setNewTransitions(transitions: PhoneStatusBarTransitions) { statusBarTransitions = transitions statusBarViewUpdatedListener?.onStatusBarViewUpdated( statusBarViewController, statusBarTransitions, ) } } Loading
packages/SystemUI/aconfig/systemui.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -453,6 +453,16 @@ flag { } } flag { name: "status_bar_always_schedule_auto_hide" namespace: "systemui" description: "Schedule the status bar auto-hide functionality more often for fullscreen mode" bug: "428659575" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "status_bar_app_handle_tracking" namespace: "systemui" Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt +137 −1 Original line number Diff line number Diff line Loading @@ -16,13 +16,16 @@ package com.android.systemui.statusbar.core import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.View import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository import com.android.systemui.dump.dumpManager import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.plugins.DarkIconDispatcher Loading @@ -36,8 +39,11 @@ import com.android.systemui.statusbar.data.model.StatusBarMode import com.android.systemui.statusbar.data.model.StatusBarMode.LIGHTS_OUT import com.android.systemui.statusbar.data.model.StatusBarMode.LIGHTS_OUT_TRANSPARENT import com.android.systemui.statusbar.data.model.StatusBarMode.OPAQUE import com.android.systemui.statusbar.data.model.StatusBarMode.SEMI_TRANSPARENT import com.android.systemui.statusbar.data.model.StatusBarMode.TRANSPARENT import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions import com.android.systemui.statusbar.phone.mockAutoHideController import com.android.systemui.statusbar.phone.ui.statusBarIconController import com.android.systemui.statusbar.policy.fakeConfigurationController import com.android.systemui.statusbar.window.data.repository.fakeStatusBarWindowStatePerDisplayRepository Loading @@ -50,7 +56,9 @@ import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.reset import org.mockito.kotlin.times import org.mockito.kotlin.verify Loading @@ -72,7 +80,6 @@ class StatusBarOrchestratorTest : SysuiTestCase() { private val fakeStatusBarWindowController = kosmos.fakeStatusBarWindowController private val fakeStatusBarInitializer = kosmos.fakeStatusBarInitializer private val dumpManager = kosmos.dumpManager private val statusBarIconRefreshInteractor = kosmos.statusBarIconRefreshInteractor private val orchestrator = kosmos.statusBarOrchestrator Loading Loading @@ -141,6 +148,135 @@ class StatusBarOrchestratorTest : SysuiTestCase() { verify(fakeStatusBarInitializer.statusBarTransitions, never()).finishAnimations() } @Test @DisableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_invokedWhenBarModeChanges_flagOff() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) setStatusBarMode(SEMI_TRANSPARENT) verify(mockAutoHideController).touchAutoHide() reset(mockAutoHideController) setStatusBarMode(OPAQUE) verify(mockAutoHideController).touchAutoHide() } @Test @EnableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_invokedWhenBarModeChanges_flagOn() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) setStatusBarMode(SEMI_TRANSPARENT) verify(mockAutoHideController).touchAutoHide() reset(mockAutoHideController) setStatusBarMode(OPAQUE) verify(mockAutoHideController).touchAutoHide() } @Test @DisableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_invokedWhenTransitionsChanges_flagOff() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) fakeStatusBarInitializer.setNewTransitions(mock<PhoneStatusBarTransitions>()) verify(mockAutoHideController).touchAutoHide() } @Test @EnableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_invokedWhenTransitionsChanges_flagOn() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) fakeStatusBarInitializer.setNewTransitions(mock<PhoneStatusBarTransitions>()) verify(mockAutoHideController).touchAutoHide() } @Test @DisableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_notInvokedWhenAnimateChanges_flagOff() = kosmos.runTest { setStatusBarMode(TRANSPARENT) setStatusBarWindowState(StatusBarWindowState.Showing) orchestrator.start() reset(mockAutoHideController) // Changing the window state will affect the `shouldAnimateNextBarModeChange` value setStatusBarWindowState(StatusBarWindowState.Hidden) verify(mockAutoHideController, never()).touchAutoHide() } @Test @EnableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_notInvokedWhenAnimateChanges_flagOn() = kosmos.runTest { setStatusBarMode(TRANSPARENT) setStatusBarWindowState(StatusBarWindowState.Showing) orchestrator.start() reset(mockAutoHideController) // Changing the window state will affect the `shouldAnimateNextBarModeChange` value setStatusBarWindowState(StatusBarWindowState.Hidden) verify(mockAutoHideController, never()).touchAutoHide() } @Test @DisableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_flagOff_notInvokedWhenTransientShownStateChanges() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) setTransientStatusBar() verify(mockAutoHideController, never()).touchAutoHide() reset(mockAutoHideController) abortTransientStatusBar() verify(mockAutoHideController, never()).touchAutoHide() } /** Regression test for b/428659575. */ @Test @EnableFlags(Flags.FLAG_STATUS_BAR_ALWAYS_SCHEDULE_AUTO_HIDE) fun autoHide_flagOn_invokedWhenTransientShownStateChanges() = kosmos.runTest { setStatusBarMode(TRANSPARENT) orchestrator.start() reset(mockAutoHideController) setTransientStatusBar() verify(mockAutoHideController).touchAutoHide() reset(mockAutoHideController) abortTransientStatusBar() verify(mockAutoHideController).touchAutoHide() } @Test fun statusBarVisible_notifiesBubbles() = testScope.runTest { Loading
packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt +37 −14 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.view.Display import android.view.View import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.Dumpable import com.android.systemui.Flags import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.demomode.DemoModeController Loading Loading @@ -133,17 +134,33 @@ constructor( statusBarWindowState != StatusBarWindowState.Hidden } private val barModeUpdate = private data class BarModeAppearance( val animate: Boolean, val barTransitions: PhoneStatusBarTransitions, val statusBarMode: StatusBarMode, val isTransientShown: Boolean, ) private val barModeAppearance = combine( shouldAnimateNextBarModeChange, phoneStatusBarTransitions.filterNotNull(), statusBarModeRepository.statusBarMode, ::Triple, statusBarModeRepository.isTransientShown, ::BarModeAppearance, ) .distinctUntilChangedBy { (_, barTransitions, statusBarMode) -> // We only want to collect when either bar transitions or status bar mode // changed. Pair(barTransitions, statusBarMode) private val barModeUpdate = barModeAppearance.distinctUntilChangedBy { // We only want to collect when either bar transitions or status bar mode changed. Pair(it.barTransitions, it.statusBarMode) } private val autoHideUpdate = barModeAppearance.distinctUntilChangedBy { // Update auto-hide whenever `isTransientShown` changes so that we always hide the // transient status bar even if `statusBarMode` hasn't changed. See b/428659575. Triple(it.barTransitions, it.statusBarMode, it.isTransientShown) } /** Starts status bar orchestration. To be called when status bar is created. */ Loading @@ -168,9 +185,12 @@ constructor( } launch { statusBarVisible.collect { updateBubblesVisibility(it) } } launch { barModeUpdate.collect { (animate, barTransitions, statusBarMode) -> updateBarMode(animate, barTransitions, statusBarMode) barModeUpdate.collect { updateBarMode(it.animate, it.barTransitions, it.statusBarMode) } } if (Flags.statusBarAlwaysScheduleAutoHide()) { launch { autoHideUpdate.collect { autoHideController.touchAutoHide() } } } } createAndAddWindow() Loading Loading @@ -238,8 +258,11 @@ constructor( if (!demoModeController.isInDemoMode) { barTransitions.transitionTo(barMode.toTransitionModeInt(), animate) } if (!Flags.statusBarAlwaysScheduleAutoHide()) { autoHideController.touchAutoHide() } } private fun updateBubblesVisibility(statusBarVisible: Boolean) { if (displayId != Display.DEFAULT_DISPLAY) { Loading
packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializer.kt +9 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ import org.mockito.kotlin.mock class FakeStatusBarInitializer : StatusBarInitializer { val statusBarViewController = mock<PhoneStatusBarViewController>() val statusBarTransitions = mock<PhoneStatusBarTransitions>() var statusBarTransitions = mock<PhoneStatusBarTransitions>() var startedByCoreStartable: Boolean = false private set Loading @@ -47,4 +47,12 @@ class FakeStatusBarInitializer : StatusBarInitializer { override fun start() { startedByCoreStartable = true } fun setNewTransitions(transitions: PhoneStatusBarTransitions) { statusBarTransitions = transitions statusBarViewUpdatedListener?.onStatusBarViewUpdated( statusBarViewController, statusBarTransitions, ) } }