Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 193d9b87 authored by Chris Göllner's avatar Chris Göllner
Browse files

Use display specific status bar window state

Before, NotificationShadeWindowViewController and others were always
retrieving the status bar window state from the default display, instead
of the one associated with the display where their view currently is.

Also makes StatusBarWindowStateController a PerDisplaySingleton instead
of SystemUISingleton, so that people are forced to think about displays
when trying to use the class.

Test: atest SystemUITests
Fixes: 420886625
Flag: com.android.systemui.shared.status_bar_connected_displays
Change-Id: I96011d2c82765174f02b11b702eb55d481072c20
parent 1e7642f8
Loading
Loading
Loading
Loading
+12 −2
Original line number Original line Diff line number Diff line
@@ -43,7 +43,9 @@ import android.view.View;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;


import com.android.app.displaylib.PerDisplayRepository;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent;
import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider;
import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider;
@@ -103,6 +105,9 @@ public class AmbientStatusBarViewControllerTest extends SysuiTestCase {
    DreamOverlayNotificationCountProvider mDreamOverlayNotificationCountProvider;
    DreamOverlayNotificationCountProvider mDreamOverlayNotificationCountProvider;
    @Mock
    @Mock
    StatusBarWindowStateController mStatusBarWindowStateController;
    StatusBarWindowStateController mStatusBarWindowStateController;
    @Mock private SystemUIDisplaySubcomponent mSystemUIDisplaySubcomponent;
    @Mock
    private PerDisplayRepository<SystemUIDisplaySubcomponent> mPerDisplaySubcomponentRepository;
    @Mock
    @Mock
    DreamOverlayStatusBarItemsProvider mDreamOverlayStatusBarItemsProvider;
    DreamOverlayStatusBarItemsProvider mDreamOverlayStatusBarItemsProvider;
    @Mock
    @Mock
@@ -143,6 +148,11 @@ public class AmbientStatusBarViewControllerTest extends SysuiTestCase {
        doCallRealMethod().when(mView).getVisibility();
        doCallRealMethod().when(mView).getVisibility();
        when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
        when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());


        when(mSystemUIDisplaySubcomponent.getStatusBarWindowStateController())
                .thenReturn(mStatusBarWindowStateController);
        when(mPerDisplaySubcomponentRepository.getOrDefault(anyInt()))
                .thenReturn(mSystemUIDisplaySubcomponent);
        when(mView.getContext()).thenReturn(getContext());
        mController = new AmbientStatusBarViewController(
        mController = new AmbientStatusBarViewController(
                mView,
                mView,
                mResources,
                mResources,
@@ -153,7 +163,7 @@ public class AmbientStatusBarViewControllerTest extends SysuiTestCase {
                mSensorPrivacyController,
                mSensorPrivacyController,
                Optional.of(mDreamOverlayNotificationCountProvider),
                Optional.of(mDreamOverlayNotificationCountProvider),
                mZenModeController,
                mZenModeController,
                mStatusBarWindowStateController,
                mPerDisplaySubcomponentRepository,
                mDreamOverlayStatusBarItemsProvider,
                mDreamOverlayStatusBarItemsProvider,
                mDreamOverlayStateController,
                mDreamOverlayStateController,
                mUserTracker,
                mUserTracker,
@@ -333,7 +343,7 @@ public class AmbientStatusBarViewControllerTest extends SysuiTestCase {
                mSensorPrivacyController,
                mSensorPrivacyController,
                Optional.empty(),
                Optional.empty(),
                mZenModeController,
                mZenModeController,
                mStatusBarWindowStateController,
                mPerDisplaySubcomponentRepository,
                mDreamOverlayStatusBarItemsProvider,
                mDreamOverlayStatusBarItemsProvider,
                mDreamOverlayStateController,
                mDreamOverlayStateController,
                mUserTracker,
                mUserTracker,
+47 −1
Original line number Original line Diff line number Diff line
@@ -25,7 +25,6 @@ import com.android.systemui.dump.dumpManager
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
import com.android.systemui.testKosmos
import com.android.systemui.util.containsExactly
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.runTest
@@ -163,6 +162,53 @@ class PerDisplayInstanceRepositoryImplTest : SysuiTestCase() {
            assertThat(displayIds).containsExactly(DEFAULT_DISPLAY_ID, NON_DEFAULT_DISPLAY_ID)
            assertThat(displayIds).containsExactly(DEFAULT_DISPLAY_ID, NON_DEFAULT_DISPLAY_ID)
        }
        }


    @Test
    fun getOrDefault_existingDisplay_returnsCorrectInstance() =
        testScope.runTest {
            val defaultInstance = underTest[DEFAULT_DISPLAY_ID]
            val nonDefaultInstance = underTest.getOrDefault(NON_DEFAULT_DISPLAY_ID)

            // The correct instance for the non-default display should be returned
            assertThat(nonDefaultInstance.displayId).isEqualTo(NON_DEFAULT_DISPLAY_ID)

            // It should NOT be the default instance
            assertThat(nonDefaultInstance).isNotSameInstanceAs(defaultInstance)
        }

    @Test
    fun getOrDefault_nonExistingDisplay_returnsDefaultInstance() =
        testScope.runTest {
            // First, get the default instance so we have something to compare against.
            val defaultInstance = underTest.getOrDefault(DEFAULT_DISPLAY_ID)

            // Now, request a display that does not exist.
            val instance = underTest.getOrDefault(NON_EXISTING_DISPLAY_ID)

            // It should fall back to returning the default instance.
            assertThat(instance).isSameInstanceAs(defaultInstance)
        }

    @Test
    fun getOrDefault_disallowedByLifecycleManager_returnsDefaultInstance() =
        testScope.runTest {
            val underTestWithLifecycle =
                kosmos.createPerDisplayInstanceRepository(
                    overrideLifecycleManager = lifecycleManager
                )

            // Allow only the default display, even though the non-default one exists.
            lifecycleManager.displayIds.value = setOf(DEFAULT_DISPLAY_ID)

            // Get the default instance to have a reference.
            val defaultInstance = underTestWithLifecycle.getOrDefault(DEFAULT_DISPLAY_ID)

            // Request the non-default display, which is disallowed by the manager.
            val instance = underTestWithLifecycle.getOrDefault(NON_DEFAULT_DISPLAY_ID)

            // It should fall back to the default instance.
            assertThat(instance).isSameInstanceAs(defaultInstance)
        }

    private fun createDisplay(displayId: Int): Display =
    private fun createDisplay(displayId: Int): Display =
        display(type = Display.TYPE_INTERNAL, id = displayId)
        display(type = Display.TYPE_INTERNAL, id = displayId)


+12 −1
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ import android.view.accessibility.AccessibilityEvent
import android.widget.FrameLayout
import android.widget.FrameLayout
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.app.displaylib.PerDisplayRepository
import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.Flags as AConfigFlags
@@ -31,6 +32,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent
import com.android.systemui.dock.DockManager
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.FakeFeatureFlags
@@ -87,6 +89,7 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mock
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.never
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.verify
@@ -121,6 +124,10 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
    private lateinit var notificationStackScrollLayoutController:
    private lateinit var notificationStackScrollLayoutController:
        NotificationStackScrollLayoutController
        NotificationStackScrollLayoutController
    @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController
    @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController
    @Mock private lateinit var systemUIDisplaySubcomponent: SystemUIDisplaySubcomponent
    @Mock
    private lateinit var perDisplaySubcomponentRepository:
        PerDisplayRepository<SystemUIDisplaySubcomponent>
    @Mock
    @Mock
    private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
    private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
    @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
    @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
@@ -174,6 +181,10 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
        whenever(dockManager.isDocked).thenReturn(false)
        whenever(dockManager.isDocked).thenReturn(false)
        whenever(keyguardTransitionInteractor.transition(Edge.create(LOCKSCREEN, DREAMING)))
        whenever(keyguardTransitionInteractor.transition(Edge.create(LOCKSCREEN, DREAMING)))
            .thenReturn(emptyFlow())
            .thenReturn(emptyFlow())
        whenever(systemUIDisplaySubcomponent.statusBarWindowStateController)
            .thenReturn(statusBarWindowStateController)
        whenever(perDisplaySubcomponentRepository.getOrDefault(anyInt()))
            .thenReturn(systemUIDisplaySubcomponent)


        val featureFlags = FakeFeatureFlags()
        val featureFlags = FakeFeatureFlags()
        featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
        featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
@@ -199,7 +210,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
                panelExpansionInteractor,
                panelExpansionInteractor,
                ShadeExpansionStateManager(),
                ShadeExpansionStateManager(),
                notificationStackScrollLayoutController,
                notificationStackScrollLayoutController,
                statusBarWindowStateController,
                perDisplaySubcomponentRepository,
                centralSurfaces,
                centralSurfaces,
                dozeServiceHost,
                dozeServiceHost,
                dozeScrimController,
                dozeScrimController,
+8 −2
Original line number Original line Diff line number Diff line
@@ -32,10 +32,12 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.VisibleForTesting;
import androidx.compose.ui.platform.ComposeView;
import androidx.compose.ui.platform.ComposeView;


import com.android.app.displaylib.PerDisplayRepository;
import com.android.systemui.ambient.statusbar.shared.flag.OngoingActivityChipsOnDream;
import com.android.systemui.ambient.statusbar.shared.flag.OngoingActivityChipsOnDream;
import com.android.systemui.ambient.statusbar.ui.binder.AmbientStatusBarViewBinder;
import com.android.systemui.ambient.statusbar.ui.binder.AmbientStatusBarViewBinder;
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor;
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent;
import com.android.systemui.dreams.DreamLogger;
import com.android.systemui.dreams.DreamLogger;
import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.DreamOverlayStateController;
@@ -72,6 +74,7 @@ import java.util.stream.Collectors;


import javax.inject.Inject;
import javax.inject.Inject;



/**
/**
 * View controller for {@link AmbientStatusBarView}.
 * View controller for {@link AmbientStatusBarView}.
 */
 */
@@ -160,7 +163,7 @@ public class AmbientStatusBarViewController extends ViewController<AmbientStatus
            IndividualSensorPrivacyController sensorPrivacyController,
            IndividualSensorPrivacyController sensorPrivacyController,
            Optional<DreamOverlayNotificationCountProvider> dreamOverlayNotificationCountProvider,
            Optional<DreamOverlayNotificationCountProvider> dreamOverlayNotificationCountProvider,
            ZenModeController zenModeController,
            ZenModeController zenModeController,
            StatusBarWindowStateController statusBarWindowStateController,
            PerDisplayRepository<SystemUIDisplaySubcomponent> perDisplaySubcomponentRepository,
            DreamOverlayStatusBarItemsProvider statusBarItemsProvider,
            DreamOverlayStatusBarItemsProvider statusBarItemsProvider,
            DreamOverlayStateController dreamOverlayStateController,
            DreamOverlayStateController dreamOverlayStateController,
            UserTracker userTracker,
            UserTracker userTracker,
@@ -178,7 +181,10 @@ public class AmbientStatusBarViewController extends ViewController<AmbientStatus
        mDateFormatUtil = dateFormatUtil;
        mDateFormatUtil = dateFormatUtil;
        mSensorPrivacyController = sensorPrivacyController;
        mSensorPrivacyController = sensorPrivacyController;
        mDreamOverlayNotificationCountProvider = dreamOverlayNotificationCountProvider;
        mDreamOverlayNotificationCountProvider = dreamOverlayNotificationCountProvider;
        mStatusBarWindowStateController = statusBarWindowStateController;
        int displayId = view.getContext().getDisplayId();
        SystemUIDisplaySubcomponent displaySubComponent =
                perDisplaySubcomponentRepository.getOrDefault(displayId);
        mStatusBarWindowStateController = displaySubComponent.getStatusBarWindowStateController();
        mStatusBarItemsProvider = statusBarItemsProvider;
        mStatusBarItemsProvider = statusBarItemsProvider;
        mZenModeController = zenModeController;
        mZenModeController = zenModeController;
        mDreamOverlayStateController = dreamOverlayStateController;
        mDreamOverlayStateController = dreamOverlayStateController;
+3 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent.PerDispla
import com.android.systemui.display.data.repository.DisplayStateRepository
import com.android.systemui.display.data.repository.DisplayStateRepository
import com.android.systemui.display.domain.interactor.DisplayStateInteractor
import com.android.systemui.display.domain.interactor.DisplayStateInteractor
import com.android.systemui.statusbar.domain.interactor.StatusBarIconRefreshInteractor
import com.android.systemui.statusbar.domain.interactor.StatusBarIconRefreshInteractor
import com.android.systemui.statusbar.window.StatusBarWindowStateController
import dagger.BindsInstance
import dagger.BindsInstance
import dagger.Subcomponent
import dagger.Subcomponent
import javax.inject.Qualifier
import javax.inject.Qualifier
@@ -49,6 +50,8 @@ interface SystemUIDisplaySubcomponent {


    @get:DisplayAware val lifecycleListeners: Set<LifecycleListener>
    @get:DisplayAware val lifecycleListeners: Set<LifecycleListener>


    @get:DisplayAware val statusBarWindowStateController: StatusBarWindowStateController

    @Subcomponent.Factory
    @Subcomponent.Factory
    interface Factory {
    interface Factory {
        fun create(@BindsInstance @DisplayId displayId: Int): SystemUIDisplaySubcomponent
        fun create(@BindsInstance @DisplayId displayId: Int): SystemUIDisplaySubcomponent
Loading