Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/PrivacyDotViewControllerTest.kt +49 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.events import android.graphics.Point import android.graphics.Rect import android.platform.test.annotations.EnableFlags import android.testing.TestableLooper.RunWithLooper import android.view.Display import android.view.DisplayAdjustments Loading @@ -26,15 +27,24 @@ import android.widget.FrameLayout import android.widget.FrameLayout.LayoutParams.UNSPECIFIED_GRAVITY import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_SHADE_WINDOW_GOES_AROUND import com.android.systemui.SysuiTestCase import com.android.systemui.display.data.repository.display import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.res.R import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository import com.android.systemui.shade.domain.interactor.shadeDisplaysInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shared.Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS import com.android.systemui.statusbar.FakeStatusBarStateController import com.android.systemui.statusbar.StatusBarState.SHADE import com.android.systemui.statusbar.events.PrivacyDotCorner.BottomLeft import com.android.systemui.statusbar.events.PrivacyDotCorner.BottomRight import com.android.systemui.statusbar.events.PrivacyDotCorner.TopLeft import com.android.systemui.statusbar.events.PrivacyDotCorner.TopRight import com.android.systemui.statusbar.layout.StatusBarContentInsetsProvider import com.android.systemui.statusbar.policy.FakeConfigurationController import com.android.systemui.testKosmos import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE Loading @@ -46,6 +56,7 @@ import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import java.util.concurrent.TimeUnit import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith Loading @@ -54,6 +65,7 @@ import org.junit.runner.RunWith @RunWithLooper class PrivacyDotViewControllerTest : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val mockDisplay = createMockDisplay() private val context = getContext().createDisplayContext(mockDisplay) Loading @@ -62,6 +74,9 @@ class PrivacyDotViewControllerTest : SysuiTestCase() { private val statusBarStateController = FakeStatusBarStateController() private val configurationController = FakeConfigurationController() private val contentInsetsProvider = createMockContentInsetsProvider() private val shadeDisplaysInteractor = kosmos.shadeDisplaysInteractor private val shadeDisplaysRepository = kosmos.fakeShadeDisplaysRepository private val shadeInteractor = kosmos.shadeInteractor private val topLeftView = initDotView() private val topRightView = initDotView() Loading @@ -81,8 +96,10 @@ class PrivacyDotViewControllerTest : SysuiTestCase() { configurationController, contentInsetsProvider, animationScheduler = mock<SystemStatusAnimationScheduler>(), shadeInteractor = null, shadeInteractor = shadeInteractor, uiExecutor = executor, displayId = DISPLAY_ID, shadeDisplaysInteractor = { shadeDisplaysInteractor }, ) @Test Loading Loading @@ -297,6 +314,36 @@ class PrivacyDotViewControllerTest : SysuiTestCase() { assertThat(controller.currentViewState.designatedCorner).isEqualTo(bottomRightView) } @Test @EnableFlags(FLAG_STATUS_BAR_CONNECTED_DISPLAYS, FLAG_SHADE_WINDOW_GOES_AROUND) fun init_shadeExpandedOnDifferentDisplay_doesNotChangeShadeExpandedState() = testScope.runTest { shadeDisplaysRepository.setDisplayId(Display.DEFAULT_DISPLAY) statusBarStateController.state = SHADE statusBarStateController.expanded = true val controller = createAndInitializeController() shadeDisplaysRepository.setDisplayId(DISPLAY_ID + 1) // other display id statusBarStateController.fakeShadeExpansionFullyChanged(true) assertThat(controller.currentViewState.shadeExpanded).isEqualTo(false) } @Test @EnableFlags(FLAG_STATUS_BAR_CONNECTED_DISPLAYS, FLAG_SHADE_WINDOW_GOES_AROUND) fun init_shadeExpandedOnThisDisplay_doesChangeShadeExpandedState() = testScope.runTest { shadeDisplaysRepository.setDisplayId(Display.DEFAULT_DISPLAY) statusBarStateController.state = SHADE statusBarStateController.expanded = false val controller = createAndInitializeController() shadeDisplaysRepository.setDisplayId(DISPLAY_ID) statusBarStateController.fakeShadeExpansionFullyChanged(true) assertThat(controller.currentViewState.shadeExpanded).isEqualTo(true) } @Test fun initialize_newViews_gravityIsUpdated() { val newTopLeftView = initDotView() Loading Loading @@ -341,6 +388,7 @@ private val CONTENT_AREA_ROTATION_SEASCAPE = Rect(left = 10, top = 40, right = 9 private val CONTENT_AREA_ROTATION_NONE = Rect(left = 20, top = 30, right = 980, bottom = 100) private val CONTENT_AREA_ROTATION_LANDSCAPE = Rect(left = 30, top = 20, right = 970, bottom = 100) private val CONTENT_AREA_ROTATION_UPSIDE_DOWN = Rect(left = 40, top = 10, right = 960, bottom = 100) private const val DISPLAY_ID = 1 private class InstantExecutor : DelayableExecutor { override fun execute(runnable: Runnable) { Loading packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt +6 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,12 @@ constructor( statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null val contentInsetsProvider = contentInsetsProviderStore.forDisplay(displayId) ?: return null val displayScope = displayScopeRepository[displayId] ?: return null return factory.create(displayScope, configurationController, contentInsetsProvider) return factory.create( displayScope, configurationController, contentInsetsProvider, displayId, ) } override suspend fun onDisplayRemovalAction(instance: PrivacyDotViewController) { Loading packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt +40 −5 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.UiThread import android.graphics.Point import android.graphics.Rect import android.util.Log import android.view.Display import android.view.View import android.widget.FrameLayout import androidx.core.animation.Animator Loading @@ -32,7 +33,9 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround import com.android.systemui.statusbar.StatusBarState.SHADE import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED import com.android.systemui.statusbar.core.StatusBarConnectedDisplays Loading @@ -51,6 +54,7 @@ import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN import com.android.systemui.util.leak.RotationUtils.Rotation import dagger.Lazy import dagger.Module import dagger.Provides import dagger.assisted.Assisted Loading @@ -58,6 +62,8 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import java.util.concurrent.Executor import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOf /** * Understands how to keep the persistent privacy dot in the corner of the screen in Loading Loading @@ -118,6 +124,8 @@ constructor( private val animationScheduler: SystemStatusAnimationScheduler, shadeInteractor: ShadeInteractor?, @ScreenDecorationsThread val uiExecutor: DelayableExecutor, @Assisted private val displayId: Int, private val shadeDisplaysInteractor: Lazy<ShadeDisplaysInteractor>?, ) : PrivacyDotViewController { private lateinit var tl: View private lateinit var tr: View Loading Loading @@ -182,9 +190,24 @@ constructor( configurationController.addCallback(configurationListener) stateController.addCallback(statusBarStateListener) scope.launch { if ( StatusBarConnectedDisplays.isEnabled && ShadeWindowGoesAround.isEnabled && shadeDisplaysInteractor != null ) { combine( shadeInteractor?.isQsExpanded ?: flowOf(false), shadeDisplaysInteractor.get().displayId, ) { _, _ -> updateStatusBarState() } } else { shadeInteractor?.isQsExpanded?.collect { isQsExpanded -> dlog("setQsExpanded $isQsExpanded") synchronized(lock) { nextViewState = nextViewState.copy(qsExpanded = isQsExpanded) } synchronized(lock) { nextViewState = nextViewState.copy(qsExpanded = isQsExpanded) } } } } } Loading Loading @@ -478,8 +501,18 @@ constructor( */ @GuardedBy("lock") private fun isShadeInQs(): Boolean { return (stateController.isExpanded && stateController.state == SHADE) || (stateController.state == SHADE_LOCKED) val isShadeExpanded = (stateController.isExpanded && stateController.state == SHADE) val isShadeExpandedOnThisDisplay = if ( StatusBarConnectedDisplays.isEnabled && ShadeWindowGoesAround.isEnabled && shadeDisplaysInteractor != null ) { isShadeExpanded && shadeDisplaysInteractor.get().displayId.value == displayId } else { isShadeExpanded } return isShadeExpandedOnThisDisplay || (stateController.state == SHADE_LOCKED) } private fun scheduleUpdate() { Loading Loading @@ -612,6 +645,7 @@ constructor( scope: CoroutineScope, configurationController: ConfigurationController, contentInsetsProvider: StatusBarContentInsetsProvider, displayId: Int, ): PrivacyDotViewControllerImpl } } Loading Loading @@ -688,6 +722,7 @@ object PrivacyDotViewControllerModule { scope, configurationController, contentInsetsProviderStore.defaultDisplay, Display.DEFAULT_DISPLAY, ) } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/PrivacyDotViewControllerTest.kt +49 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.events import android.graphics.Point import android.graphics.Rect import android.platform.test.annotations.EnableFlags import android.testing.TestableLooper.RunWithLooper import android.view.Display import android.view.DisplayAdjustments Loading @@ -26,15 +27,24 @@ import android.widget.FrameLayout import android.widget.FrameLayout.LayoutParams.UNSPECIFIED_GRAVITY import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_SHADE_WINDOW_GOES_AROUND import com.android.systemui.SysuiTestCase import com.android.systemui.display.data.repository.display import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.res.R import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository import com.android.systemui.shade.domain.interactor.shadeDisplaysInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shared.Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS import com.android.systemui.statusbar.FakeStatusBarStateController import com.android.systemui.statusbar.StatusBarState.SHADE import com.android.systemui.statusbar.events.PrivacyDotCorner.BottomLeft import com.android.systemui.statusbar.events.PrivacyDotCorner.BottomRight import com.android.systemui.statusbar.events.PrivacyDotCorner.TopLeft import com.android.systemui.statusbar.events.PrivacyDotCorner.TopRight import com.android.systemui.statusbar.layout.StatusBarContentInsetsProvider import com.android.systemui.statusbar.policy.FakeConfigurationController import com.android.systemui.testKosmos import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE Loading @@ -46,6 +56,7 @@ import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import java.util.concurrent.TimeUnit import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith Loading @@ -54,6 +65,7 @@ import org.junit.runner.RunWith @RunWithLooper class PrivacyDotViewControllerTest : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val mockDisplay = createMockDisplay() private val context = getContext().createDisplayContext(mockDisplay) Loading @@ -62,6 +74,9 @@ class PrivacyDotViewControllerTest : SysuiTestCase() { private val statusBarStateController = FakeStatusBarStateController() private val configurationController = FakeConfigurationController() private val contentInsetsProvider = createMockContentInsetsProvider() private val shadeDisplaysInteractor = kosmos.shadeDisplaysInteractor private val shadeDisplaysRepository = kosmos.fakeShadeDisplaysRepository private val shadeInteractor = kosmos.shadeInteractor private val topLeftView = initDotView() private val topRightView = initDotView() Loading @@ -81,8 +96,10 @@ class PrivacyDotViewControllerTest : SysuiTestCase() { configurationController, contentInsetsProvider, animationScheduler = mock<SystemStatusAnimationScheduler>(), shadeInteractor = null, shadeInteractor = shadeInteractor, uiExecutor = executor, displayId = DISPLAY_ID, shadeDisplaysInteractor = { shadeDisplaysInteractor }, ) @Test Loading Loading @@ -297,6 +314,36 @@ class PrivacyDotViewControllerTest : SysuiTestCase() { assertThat(controller.currentViewState.designatedCorner).isEqualTo(bottomRightView) } @Test @EnableFlags(FLAG_STATUS_BAR_CONNECTED_DISPLAYS, FLAG_SHADE_WINDOW_GOES_AROUND) fun init_shadeExpandedOnDifferentDisplay_doesNotChangeShadeExpandedState() = testScope.runTest { shadeDisplaysRepository.setDisplayId(Display.DEFAULT_DISPLAY) statusBarStateController.state = SHADE statusBarStateController.expanded = true val controller = createAndInitializeController() shadeDisplaysRepository.setDisplayId(DISPLAY_ID + 1) // other display id statusBarStateController.fakeShadeExpansionFullyChanged(true) assertThat(controller.currentViewState.shadeExpanded).isEqualTo(false) } @Test @EnableFlags(FLAG_STATUS_BAR_CONNECTED_DISPLAYS, FLAG_SHADE_WINDOW_GOES_AROUND) fun init_shadeExpandedOnThisDisplay_doesChangeShadeExpandedState() = testScope.runTest { shadeDisplaysRepository.setDisplayId(Display.DEFAULT_DISPLAY) statusBarStateController.state = SHADE statusBarStateController.expanded = false val controller = createAndInitializeController() shadeDisplaysRepository.setDisplayId(DISPLAY_ID) statusBarStateController.fakeShadeExpansionFullyChanged(true) assertThat(controller.currentViewState.shadeExpanded).isEqualTo(true) } @Test fun initialize_newViews_gravityIsUpdated() { val newTopLeftView = initDotView() Loading Loading @@ -341,6 +388,7 @@ private val CONTENT_AREA_ROTATION_SEASCAPE = Rect(left = 10, top = 40, right = 9 private val CONTENT_AREA_ROTATION_NONE = Rect(left = 20, top = 30, right = 980, bottom = 100) private val CONTENT_AREA_ROTATION_LANDSCAPE = Rect(left = 30, top = 20, right = 970, bottom = 100) private val CONTENT_AREA_ROTATION_UPSIDE_DOWN = Rect(left = 40, top = 10, right = 960, bottom = 100) private const val DISPLAY_ID = 1 private class InstantExecutor : DelayableExecutor { override fun execute(runnable: Runnable) { Loading
packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt +6 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,12 @@ constructor( statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null val contentInsetsProvider = contentInsetsProviderStore.forDisplay(displayId) ?: return null val displayScope = displayScopeRepository[displayId] ?: return null return factory.create(displayScope, configurationController, contentInsetsProvider) return factory.create( displayScope, configurationController, contentInsetsProvider, displayId, ) } override suspend fun onDisplayRemovalAction(instance: PrivacyDotViewController) { Loading
packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt +40 −5 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.UiThread import android.graphics.Point import android.graphics.Rect import android.util.Log import android.view.Display import android.view.View import android.widget.FrameLayout import androidx.core.animation.Animator Loading @@ -32,7 +33,9 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround import com.android.systemui.statusbar.StatusBarState.SHADE import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED import com.android.systemui.statusbar.core.StatusBarConnectedDisplays Loading @@ -51,6 +54,7 @@ import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN import com.android.systemui.util.leak.RotationUtils.Rotation import dagger.Lazy import dagger.Module import dagger.Provides import dagger.assisted.Assisted Loading @@ -58,6 +62,8 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import java.util.concurrent.Executor import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOf /** * Understands how to keep the persistent privacy dot in the corner of the screen in Loading Loading @@ -118,6 +124,8 @@ constructor( private val animationScheduler: SystemStatusAnimationScheduler, shadeInteractor: ShadeInteractor?, @ScreenDecorationsThread val uiExecutor: DelayableExecutor, @Assisted private val displayId: Int, private val shadeDisplaysInteractor: Lazy<ShadeDisplaysInteractor>?, ) : PrivacyDotViewController { private lateinit var tl: View private lateinit var tr: View Loading Loading @@ -182,9 +190,24 @@ constructor( configurationController.addCallback(configurationListener) stateController.addCallback(statusBarStateListener) scope.launch { if ( StatusBarConnectedDisplays.isEnabled && ShadeWindowGoesAround.isEnabled && shadeDisplaysInteractor != null ) { combine( shadeInteractor?.isQsExpanded ?: flowOf(false), shadeDisplaysInteractor.get().displayId, ) { _, _ -> updateStatusBarState() } } else { shadeInteractor?.isQsExpanded?.collect { isQsExpanded -> dlog("setQsExpanded $isQsExpanded") synchronized(lock) { nextViewState = nextViewState.copy(qsExpanded = isQsExpanded) } synchronized(lock) { nextViewState = nextViewState.copy(qsExpanded = isQsExpanded) } } } } } Loading Loading @@ -478,8 +501,18 @@ constructor( */ @GuardedBy("lock") private fun isShadeInQs(): Boolean { return (stateController.isExpanded && stateController.state == SHADE) || (stateController.state == SHADE_LOCKED) val isShadeExpanded = (stateController.isExpanded && stateController.state == SHADE) val isShadeExpandedOnThisDisplay = if ( StatusBarConnectedDisplays.isEnabled && ShadeWindowGoesAround.isEnabled && shadeDisplaysInteractor != null ) { isShadeExpanded && shadeDisplaysInteractor.get().displayId.value == displayId } else { isShadeExpanded } return isShadeExpandedOnThisDisplay || (stateController.state == SHADE_LOCKED) } private fun scheduleUpdate() { Loading Loading @@ -612,6 +645,7 @@ constructor( scope: CoroutineScope, configurationController: ConfigurationController, contentInsetsProvider: StatusBarContentInsetsProvider, displayId: Int, ): PrivacyDotViewControllerImpl } } Loading Loading @@ -688,6 +722,7 @@ object PrivacyDotViewControllerModule { scope, configurationController, contentInsetsProviderStore.defaultDisplay, Display.DEFAULT_DISPLAY, ) } }