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

Commit 76ef4169 authored by Steven Ng's avatar Steven Ng Committed by Android (Google) Code Review
Browse files

Merge "Show an empty presentation in connected displays during device provisioning" into main

parents 0a699200 c296db8e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ class KeyguardDisplayManagerTest : SysuiTestCase() {
                presentationFactory,
                { shadePositionRepository },
                testScope.backgroundScope,
                /* isCentralizedWallpaperPresentationEnabled= */ false,
            )
        whenever(presentationFactory.create(any())).doReturn(connectedDisplayKeyguardPresentation)

+184 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.wallpapers

import android.app.Presentation
import android.hardware.display.DisplayManagerGlobal
import android.view.Display
import android.view.DisplayAdjustments
import android.view.DisplayInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.wallpapers.domain.interactor.DisplayWallpaperPresentationInteractor.WallpaperPresentationType.KEYGUARD
import com.android.systemui.wallpapers.domain.interactor.DisplayWallpaperPresentationInteractor.WallpaperPresentationType.NONE
import com.android.systemui.wallpapers.domain.interactor.DisplayWallpaperPresentationInteractor.WallpaperPresentationType.PROVISIONING
import com.android.systemui.wallpapers.domain.interactor.fakeDisplayWallpaperPresentationInteractor
import com.android.systemui.wallpapers.ui.presentation.KeyguardWallpaperPresentationFactory
import com.android.systemui.wallpapers.ui.presentation.ProvisioningWallpaperPresentationFactory
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoInteractions
import org.mockito.kotlin.verifyNoMoreInteractions

@SmallTest
@RunWith(AndroidJUnit4::class)
class WallpaperPresentationManagerTest : SysuiTestCase() {
    private val kosmos = Kosmos().useUnconfinedTestDispatcher()
    private val testScope = kosmos.testScope
    private val fakeWallpaperPresentationInteractor =
        kosmos.fakeDisplayWallpaperPresentationInteractor
    private val testDisplay: Display =
        Display(
            DisplayManagerGlobal.getInstance(),
            /* displayId= */ 2,
            DisplayInfo(),
            DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS,
        )

    private val provisioningPresentation: Presentation = mock()
    private val provisioningPresentationFactory: ProvisioningWallpaperPresentationFactory = mock {
        on { create(any()) }.doReturn(provisioningPresentation)
    }
    private val keyguardPresentation: Presentation = mock()
    private val keyguardPresentationFactory: KeyguardWallpaperPresentationFactory = mock {
        on { create(any()) }.doReturn(keyguardPresentation)
    }

    private val wallpaperPresentationManager =
        WallpaperPresentationManager(
            display = testDisplay,
            displayCoroutineScope = testScope.backgroundScope,
            presentationInteractor = kosmos.fakeDisplayWallpaperPresentationInteractor,
            presentationFactories =
                mapOf(
                    PROVISIONING to provisioningPresentationFactory,
                    KEYGUARD to keyguardPresentationFactory,
                ),
            appCoroutineScope = testScope,
            mainDispatcher = kosmos.testDispatcher,
        )

    @Test
    fun emitProvisioning_createProvisioningPresentation() =
        kosmos.runTest {
            wallpaperPresentationManager.start()

            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(PROVISIONING)

            verify(provisioningPresentationFactory).create(eq(testDisplay))
            verify(provisioningPresentation).show()
            verifyNoMoreInteractions(provisioningPresentation)
            verifyNoInteractions(keyguardPresentationFactory)
        }

    @Test
    fun emitProvisioningThenNone_hideProvisioningPresentation() =
        kosmos.runTest {
            wallpaperPresentationManager.start()

            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(PROVISIONING)
            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(NONE)

            verify(provisioningPresentation).hide()
            verifyNoInteractions(keyguardPresentationFactory)
        }

    @Test
    fun emitProvisioningThenKeyguard_hideProvisioningAndShowKeyguardPresentation() =
        kosmos.runTest {
            wallpaperPresentationManager.start()

            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(PROVISIONING)
            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(KEYGUARD)

            verify(provisioningPresentation).hide()
            verify(keyguardPresentationFactory).create(eq(testDisplay))
            verify(keyguardPresentation).show()
            verifyNoMoreInteractions(keyguardPresentation)
        }

    @Test
    fun emitKeyguard_showKeyguardPresentation() =
        kosmos.runTest {
            wallpaperPresentationManager.start()

            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(KEYGUARD)

            verify(keyguardPresentationFactory).create(eq(testDisplay))
            verify(keyguardPresentation).show()
            verifyNoMoreInteractions(keyguardPresentation)
            verifyNoInteractions(provisioningPresentationFactory)
        }

    @Test
    fun emitKeyguardThenNone_hideKeyguardPresentation() =
        kosmos.runTest {
            wallpaperPresentationManager.start()

            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(KEYGUARD)
            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(NONE)

            verify(keyguardPresentation).hide()
            verifyNoInteractions(provisioningPresentationFactory)
        }

    @Test
    fun emitKeyguardThenProvisioning_hideKeyguardAndShowProvisioningPresentation() =
        kosmos.runTest {
            wallpaperPresentationManager.start()

            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(KEYGUARD)
            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(PROVISIONING)

            verify(keyguardPresentation).hide()
            verify(provisioningPresentation).show()
            verifyNoMoreInteractions(provisioningPresentation)
        }

    @Test
    fun stop_hidePreviouslyShownProvisioningPresentation() =
        kosmos.runTest {
            wallpaperPresentationManager.start()
            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(PROVISIONING)

            wallpaperPresentationManager.stop()

            verify(provisioningPresentation).hide()
        }

    @Test
    fun stop_hidePreviouslyShownKeyguardPresentation() =
        kosmos.runTest {
            wallpaperPresentationManager.start()
            fakeWallpaperPresentationInteractor._presentationFactoryFlow.emit(KEYGUARD)

            wallpaperPresentationManager.stop()

            verify(keyguardPresentation).hide()
        }
}
+136 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.wallpapers.domain.interactor

import android.hardware.display.DisplayManagerGlobal
import android.view.Display
import android.view.DisplayAdjustments
import android.view.DisplayInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.keyguardDisplayManager
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
import com.android.systemui.testKosmos
import com.android.systemui.wallpapers.domain.interactor.DisplayWallpaperPresentationInteractor.WallpaperPresentationType.KEYGUARD
import com.android.systemui.wallpapers.domain.interactor.DisplayWallpaperPresentationInteractor.WallpaperPresentationType.NONE
import com.android.systemui.wallpapers.domain.interactor.DisplayWallpaperPresentationInteractor.WallpaperPresentationType.PROVISIONING
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Before
import org.junit.runner.RunWith

@ExperimentalCoroutinesApi
@SmallTest
@RunWith(AndroidJUnit4::class)
class DisplayWallpaperPresentationInteractorTest : SysuiTestCase() {
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val deviceUnlockedInteractor = kosmos.keyguardInteractor
    private val fakeKeyguardRepository = kosmos.fakeKeyguardRepository
    private val deviceProvisioningRepository = kosmos.fakeDeviceProvisioningRepository
    private val keyguardDisplayManager = kosmos.keyguardDisplayManager
    private val testDisplayInfo = DisplayInfo()
    private val testDisplay: Display =
        Display(
            DisplayManagerGlobal.getInstance(),
            /* displayId= */ 2,
            testDisplayInfo,
            DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS,
        )
    private val wallpaperPresentationInteractor =
        DisplayWallpaperPresentationInteractorImpl(
            display = testDisplay,
            displayCoroutineScope = kosmos.testScope.backgroundScope,
            keyguardInteractor = { deviceUnlockedInteractor },
            deviceProvisioningRepository = { deviceProvisioningRepository },
            keyguardDisplayManager = { keyguardDisplayManager },
        )

    @Before
    fun setUp() {
        fakeKeyguardRepository.setKeyguardDismissible(isUnlocked = true)
        deviceProvisioningRepository.setDeviceProvisioned(true)
    }

    @Test
    fun presentationFactoryFlow_unlocked_provisioned_none() =
        kosmos.runTest {
            fakeKeyguardRepository.setKeyguardDismissible(isUnlocked = true)
            deviceProvisioningRepository.setDeviceProvisioned(true)

            val actual by collectLastValue(wallpaperPresentationInteractor.presentationFactoryFlow)
            assertThat(actual).isEqualTo(NONE)
        }

    @Test
    fun presentationFactoryFlow_locked_provisioned_displayCompatible_keyguard() =
        kosmos.runTest {
            fakeKeyguardRepository.setKeyguardDismissible(isUnlocked = false)
            deviceProvisioningRepository.setDeviceProvisioned(true)

            val actual by collectLastValue(wallpaperPresentationInteractor.presentationFactoryFlow)
            assertThat(actual).isEqualTo(KEYGUARD)
        }

    @Test
    fun presentationFactoryFlow_locked_provisioned_displayIncompatible_none() =
        kosmos.runTest {
            testDisplayInfo.flags = Display.FLAG_PRIVATE
            fakeKeyguardRepository.setKeyguardDismissible(isUnlocked = false)
            deviceProvisioningRepository.setDeviceProvisioned(true)

            val actual by collectLastValue(wallpaperPresentationInteractor.presentationFactoryFlow)
            assertThat(actual).isEqualTo(NONE)
        }

    @Test
    fun presentationFactoryFlow_provisioning_locked_displayCompatible_provisioning() =
        kosmos.runTest {
            deviceProvisioningRepository.setDeviceProvisioned(false)
            fakeKeyguardRepository.setKeyguardDismissible(isUnlocked = false)

            val actual by collectLastValue(wallpaperPresentationInteractor.presentationFactoryFlow)
            assertThat(actual).isEqualTo(PROVISIONING)
        }

    @Test
    fun presentationFactoryFlow_provisioning_unlocked_displayCompatible_provisioning() =
        kosmos.runTest {
            deviceProvisioningRepository.setDeviceProvisioned(false)
            fakeKeyguardRepository.setKeyguardDismissible(isUnlocked = true)

            val actual by collectLastValue(wallpaperPresentationInteractor.presentationFactoryFlow)
            assertThat(actual).isEqualTo(PROVISIONING)
        }

    @Test
    fun presentationFactoryFlow_provisioning_displayIncompatible_none() =
        kosmos.runTest {
            testDisplayInfo.flags = Display.FLAG_PRIVATE
            deviceProvisioningRepository.setDeviceProvisioned(false)

            val actual by collectLastValue(wallpaperPresentationInteractor.presentationFactoryFlow)
            assertThat(actual).isEqualTo(NONE)
        }
}
+8 −0
Original line number Diff line number Diff line
@@ -203,4 +203,12 @@
      </item>
      <item name="android:textSize">@dimen/bouncer_user_switcher_item_text_size</item>
    </style>

    <style name="Theme.SystemUI.WallpaperPresentation">
        <item name="android:windowActionBar">false</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:colorBackground">@android:color/transparent</item>
    </style>
</resources>
+30 −8
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import com.android.systemui.shade.ShadeDisplayAware;
import com.android.systemui.shade.data.repository.ShadeDisplaysRepository;
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.wallpapers.WallpaperPresentationEnabled;

import dagger.Lazy;

@@ -71,6 +72,7 @@ public class KeyguardDisplayManager {
    private final Provider<ShadeDisplaysRepository> mShadePositionRepositoryProvider;
    private final ConnectedDisplayKeyguardPresentationFactory
            mConnectedDisplayKeyguardPresentationFactory;
    private final Boolean mIsCentralizedWallpaperPresentationEnabled;
    private final Context mContext;

    private boolean mShowing;
@@ -116,7 +118,8 @@ public class KeyguardDisplayManager {
            ConnectedDisplayKeyguardPresentationFactory
                    connectedDisplayKeyguardPresentationFactory,
            Provider<ShadeDisplaysRepository> shadePositionRepositoryProvider,
            @Application CoroutineScope appScope) {
            @Application CoroutineScope appScope,
            @WallpaperPresentationEnabled Boolean isCentralizedWallpaperPresentationEnabled) {
        mContext = context;
        mNavigationBarControllerLazy = navigationBarControllerLazy;
        mShadePositionRepositoryProvider = shadePositionRepositoryProvider;
@@ -127,6 +130,7 @@ public class KeyguardDisplayManager {
        mDeviceStateHelper = deviceStateHelper;
        mKeyguardStateController = keyguardStateController;
        mConnectedDisplayKeyguardPresentationFactory = connectedDisplayKeyguardPresentationFactory;
        mIsCentralizedWallpaperPresentationEnabled = isCentralizedWallpaperPresentationEnabled;
        if (ShadeWindowGoesAround.isEnabled()) {
            collectFlow(appScope, shadePositionRepositoryProvider.get().getDisplayId(),
                    (id) -> onShadeWindowMovedToDisplayId(id));
@@ -140,7 +144,10 @@ public class KeyguardDisplayManager {
        }
    }

    private boolean isKeyguardShowable(Display display) {
    /**
     * Returns `true` if the keyguard can be shown for a given {@code display}. Otherwise, `false`.
     */
    public boolean isKeyguardShowable(Display display) {
        if (display == null) {
            Log.i(TAG, "Cannot show Keyguard on null display");
            return false;
@@ -193,6 +200,10 @@ public class KeyguardDisplayManager {
     *         was already there.
     */
    private boolean showPresentation(Display display) {
        if (mIsCentralizedWallpaperPresentationEnabled) {
            // Handled in WallpaperPresentationManager.
            return false;
        }
        if (!isKeyguardShowable(display)) return false;
        Log.i(TAG, "Keyguard enabled on display: " + display);
        final int displayId = display.getDisplayId();
@@ -227,6 +238,10 @@ public class KeyguardDisplayManager {
     * @param displayId The id of the display to hide the presentation off.
     */
    private void hidePresentation(int displayId) {
        if (mIsCentralizedWallpaperPresentationEnabled) {
            // Handled in WallpaperPresentationManager.
            return;
        }
        final Presentation presentation = mPresentations.get(displayId);
        if (presentation != null) {
            presentation.dismiss();
@@ -289,6 +304,12 @@ public class KeyguardDisplayManager {
                updateNavigationBarVisibility(displayId, false /* navBarVisible */);
                changed |= showPresentation(display);
            }
        } else {
            if (mIsCentralizedWallpaperPresentationEnabled) {
                for (Display display : mDisplayTracker.getAllDisplays()) {
                    int displayId = display.getDisplayId();
                    updateNavigationBarVisibility(displayId, true /* navBarVisible */);
                }
            } else {
                changed = mPresentations.size() > 0;
                for (int i = mPresentations.size() - 1; i >= 0; i--) {
@@ -298,6 +319,7 @@ public class KeyguardDisplayManager {
                }
                mPresentations.clear();
            }
        }
        return changed;
    }

Loading