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

Commit f5c8e3e1 authored by Steven Ng's avatar Steven Ng
Browse files

Manage wallpaper connections on display changes

There are three different type of wallpapers
1. Fallback wallpaper: used when the user selected wallpaper doesn't support the added display.
2. System wallpaper: a user selected wallpaper or default. Used in external displays when supported.
3. Lock wallpaper: if the user selects a wallpaper specifically for the lock screen.

Also, make the following changes in SysUi to show wallpaper in connected display keyguard:
1. Make the background of ConnectedDisplayKeyguardPresentation transparent.
2. Add FLAG_SHOW_WALLPAPER to ConnectedDisplayKeyguardPresentation's window

TODO:
1. The logic for determining if a wallpaper supports an added display will be added in a subsequent CL.
2. The updateFallbackConnection will be updated to handle multi displays in a subsequent CL.

Test: atests FrameworksMockingServicesTests:WallpaperManagerServiceTests. Also, connect to an external display to test wallpapers are shown correctly in home screen and keyguard.
Flag: android.app.enable_connected_displays_wallpaper
Bug: 384520326
Change-Id: Ieca76e8e67af8f12afc145b3dc6050771e3419d3
parent 878ba923
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -128,7 +128,7 @@
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:colorBackground">@*android:color/background_material_dark</item>
        <item name="android:colorBackground">@android:color/transparent</item>
    </style>

    <style name="TextAppearance.Keyguard">
+4 −0
Original line number Diff line number Diff line
@@ -91,6 +91,10 @@ constructor(
        super.onCreate(savedInstanceState)

        onCreateV2()
        val window = window ?: return
        val layoutParams = window.attributes
        layoutParams.flags = layoutParams.flags or WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
        window.attributes = layoutParams
    }

    fun onCreateV2() {
+103 −24
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_WALLPAPER_INTERNAL;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.Flags.enableConnectedDisplaysWallpaper;
import static android.app.Flags.fixWallpaperChanged;
import static android.app.Flags.liveWallpaperContentHandling;
import static android.app.Flags.removeNextWallpaperComponent;
@@ -89,6 +90,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.multiuser.Flags;
import android.os.Binder;
import android.os.Bundle;
@@ -655,8 +657,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
    private final MyPackageMonitor mMonitor;
    private final AppOpsManager mAppOpsManager;

    private final DisplayManager.DisplayListener mDisplayListener =
            new DisplayManager.DisplayListener() {
    private final DisplayListener mDisplayListener = new DisplayListener() {

        @Override
        public void onDisplayAdded(int displayId) {
@@ -665,24 +666,64 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        @Override
        public void onDisplayRemoved(int displayId) {
            synchronized (mLock) {
                if (enableConnectedDisplaysWallpaper()) {
                    // There could be at most 2 wallpaper connections per display:
                    // 1. system & lock are the same: mLastWallpaper
                    // 2. system, lock are different: mLastWallpaper, mLastLockWallpaper
                    // 3. fallback used as both system & lock wallpaper: mFallbackWallpaper
                    // 4. fallback used as lock only wallpaper: mFallbackWallpaper,
                    //    mLastWallpaper
                    // 5. fallback used as system only wallpaper: mFallbackWallpaper,
                    //    mLastLockWallpaper
                    List<WallpaperData> pendingDisconnectWallpapers = new ArrayList<>();
                    if (mLastWallpaper != null && mLastWallpaper.connection != null
                            && mLastWallpaper.connection.containsDisplay(displayId)) {
                        pendingDisconnectWallpapers.add(mLastWallpaper);
                    }
                    if (mLastLockWallpaper != null && mLastLockWallpaper.connection != null
                            && mLastLockWallpaper.connection.containsDisplay(displayId)) {
                        pendingDisconnectWallpapers.add(mLastLockWallpaper);
                    }
                    if (mFallbackWallpaper != null && mFallbackWallpaper.connection != null
                            && mFallbackWallpaper.connection.containsDisplay(displayId)) {
                        pendingDisconnectWallpapers.add(mFallbackWallpaper);
                    }
                    for (int i = 0; i < pendingDisconnectWallpapers.size(); i++) {
                        WallpaperData wallpaper = pendingDisconnectWallpapers.get(i);
                        DisplayConnector displayConnector =
                                wallpaper.connection.getDisplayConnectorOrCreate(displayId);
                        if (displayConnector == null) {
                            Slog.w(TAG,
                                    "Fail to disconnect wallpaper upon display removal");
                            return;
                        }
                        displayConnector.disconnectLocked(wallpaper.connection);
                        wallpaper.connection.removeDisplayConnector(displayId);
                    }
                } else {
                    if (mLastWallpaper != null) {
                        WallpaperData targetWallpaper = null;
                    if (mLastWallpaper.connection != null &&
                            mLastWallpaper.connection.containsDisplay(displayId)) {
                        if (mLastWallpaper.connection != null
                                && mLastWallpaper.connection.containsDisplay(displayId)) {
                            targetWallpaper = mLastWallpaper;
                    } else if (mFallbackWallpaper != null &&
                            mFallbackWallpaper.connection != null &&
                            mFallbackWallpaper.connection.containsDisplay(displayId)) {
                        } else if (mFallbackWallpaper != null
                                && mFallbackWallpaper.connection != null
                                && mFallbackWallpaper.connection.containsDisplay(
                                displayId)) {
                            targetWallpaper = mFallbackWallpaper;
                        }
                        if (targetWallpaper == null) return;
                        DisplayConnector connector =
                            targetWallpaper.connection.getDisplayConnectorOrCreate(displayId);
                                targetWallpaper.connection.getDisplayConnectorOrCreate(
                                        displayId);
                        if (connector == null) return;
                        connector.disconnectLocked(targetWallpaper.connection);
                        targetWallpaper.connection.removeDisplayConnector(displayId);
                    mWallpaperDisplayHelper.removeDisplayData(displayId);
                    }
                }

                mWallpaperDisplayHelper.removeDisplayData(displayId);

                for (int i = mColorsChangedListeners.size() - 1; i >= 0; i--) {
                    final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> callbacks =
                            mColorsChangedListeners.valueAt(i);
@@ -1627,6 +1668,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        public void onScreenTurnedOn(int displayId) {
            notifyScreenTurnedOn(displayId);
        }

        @Override
        public void onScreenTurningOn(int displayId) {
            notifyScreenTurningOn(displayId);
@@ -3707,6 +3749,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        }
        if (newWallpaper.mWhich == (FLAG_SYSTEM | FLAG_LOCK)) {
            mLastWallpaper = newWallpaper;
            mLastLockWallpaper = null;
        } else if (newWallpaper.mWhich == FLAG_SYSTEM) {
            mLastWallpaper = newWallpaper;
        } else if (newWallpaper.mWhich == FLAG_LOCK) {
@@ -3916,6 +3959,40 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
            if (mLastWallpaper == null) {
                return;
            }
            if (enableConnectedDisplaysWallpaper()) {
                int useFallbackWallpaperWhich = 0;
                List<WallpaperData> wallpapers = new ArrayList<>();
                wallpapers.add(mLastWallpaper);
                // If the system and the lock wallpapers are not the same, we should also
                // establish a display connector to the lock wallpaper for this display.
                if (mLastLockWallpaper != null && mLastWallpaper != mLastLockWallpaper) {
                    wallpapers.add(mLastLockWallpaper);
                }

                for (int i = 0; i < wallpapers.size(); i++) {
                    WallpaperData wallpaper = wallpapers.get(i);
                    if (supportsMultiDisplay(wallpaper.connection)) {
                        final DisplayConnector connector =
                                wallpaper.connection.getDisplayConnectorOrCreate(displayId);
                        if (connector != null) {
                            connector.connectLocked(wallpaper.connection, wallpaper);
                        } else {
                            Slog.w(TAG, "Fail to connect to wallpaper for display id " + displayId
                                    + " due to null connector. Use fallback wallpaper.");
                            useFallbackWallpaperWhich |= wallpaper.mWhich;
                        }
                    } else {
                        useFallbackWallpaperWhich |= wallpaper.mWhich;
                    }
                }

                if (useFallbackWallpaperWhich == 0
                        || mFallbackWallpaper == null
                        || mFallbackWallpaper.connection == null) {
                    return;
                }
                mFallbackWallpaper.mWhich = useFallbackWallpaperWhich;
            } else {
                if (supportsMultiDisplay(mLastWallpaper.connection)) {
                    final DisplayConnector connector =
                            mLastWallpaper.connection.getDisplayConnectorOrCreate(displayId);
@@ -3923,6 +4000,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
                    connector.connectLocked(mLastWallpaper.connection, mLastWallpaper);
                    return;
                }
            }

            // System wallpaper does not support multiple displays, attach this display to
            // the fallback wallpaper.
            if (mFallbackWallpaper != null && mFallbackWallpaper
+256 −2
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertEquals;
@@ -65,6 +66,7 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.ServiceInfo;
import android.graphics.Color;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -75,6 +77,7 @@ import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
import android.service.wallpaper.WallpaperService;
import android.testing.TestableContext;
import android.util.Log;
@@ -105,6 +108,7 @@ import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.quality.Strictness;
@@ -154,6 +158,8 @@ public class WallpaperManagerServiceTests {
    private WallpaperManagerService mService;
    private static IWallpaperConnection.Stub sWallpaperService;

    private static WindowManagerInternal sWindowManagerInternal;

    @BeforeClass
    public static void setUpClass() {
        sMockitoSession = mockitoSession()
@@ -163,8 +169,8 @@ public class WallpaperManagerServiceTests {
                .spyStatic(WallpaperManager.class)
                .startMocking();

        final WindowManagerInternal dmi = mock(WindowManagerInternal.class);
        LocalServices.addService(WindowManagerInternal.class, dmi);
        sWindowManagerInternal = mock(WindowManagerInternal.class);
        LocalServices.addService(WindowManagerInternal.class, sWindowManagerInternal);

        sContext.addMockSystemService(Context.APP_OPS_SERVICE, mock(AppOpsManager.class));

@@ -335,6 +341,43 @@ public class WallpaperManagerServiceTests {
        verifyCurrentSystemData(testUserId);
    }

    /**
     * Test setWallpaperComponent with FLAG_LOCK should update the mLastLockWallpaper.
     */
    @Test
    public void testSetLockWallpaper() {
        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        verifyLastWallpaperData(testUserId, sDefaultWallpaperComponent);
        verifyCurrentSystemData(testUserId);

        mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(),
                FLAG_LOCK, testUserId);
        verifyLastLockWallpaperData(testUserId, sImageWallpaperComponentName);
        verifyCurrentSystemData(testUserId);
    }

    /**
     * Test setWallpaperComponent with FLAG_LOCK and then setWallpaperComponent with
     * FLAG_LOCK | FLAG_SYSTEM should set mLastLockWallpaper to null.
     */
    @Test
    public void testSetLockWallpaperThenSetLockAndSystemWallpaper_setLastLockWallpaperToNull() {
        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        verifyLastWallpaperData(testUserId, sDefaultWallpaperComponent);
        verifyCurrentSystemData(testUserId);

        mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(),
                FLAG_LOCK, testUserId);
        mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(),
                FLAG_LOCK | FLAG_SYSTEM, testUserId);

        verifyLastWallpaperData(testUserId, sImageWallpaperComponentName);
        assertThat(mService.mLastLockWallpaper).isNull();
        verifyCurrentSystemData(testUserId);
    }

    /**
     * Tests that when setWallpaperComponent is called with the currently set component, a command
     * is issued to the wallpaper.
@@ -661,6 +704,171 @@ public class WallpaperManagerServiceTests {
        assertPfdAndFileContentsEqual(pfd, originalSystemWallpaperFile);
    }

    // Verify a secondary display added started
    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER)
    public void displayAdded_sameSystemAndLockWallpaper_shouldAttachWallpaperServiceOnce()
            throws Exception {
        // GIVEN the same wallpaper used for the lock and system.
        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        final WallpaperData wallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM, testUserId);
        IWallpaperService mockIWallpaperService = mock(IWallpaperService.class);
        wallpaper.connection.mService = mockIWallpaperService;
        // GIVEN there are two displays: DEFAULT_DISPLAY, 2
        final int testDisplayId = 2;
        setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId));

        // WHEN displayId, 2, is ready.
        WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService(
                WallpaperManagerInternal.class);
        wallpaperManagerInternal.onDisplayReady(testDisplayId);

        // Then there is a connection established for the system & lock wallpaper for display ID, 2.
        verify(mockIWallpaperService).attach(
                /* connection= */ eq(wallpaper.connection),
                /* windowToken= */ any(),
                /* windowType= */ anyInt(),
                /* isPreview= */ anyBoolean(),
                /* reqWidth= */ anyInt(),
                /* reqHeight= */ anyInt(),
                /* padding= */ any(),
                /* displayId= */ eq(testDisplayId),
                /* which= */ eq(FLAG_SYSTEM | FLAG_LOCK),
                /* info= */ any(),
                /* description= */ any());
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER)
    public void displayAdded_differentSystemAndLockWallpapers_shouldAttachWallpaperServiceTwice()
            throws Exception {
        // GIVEN different wallpapers used for the lock and system.
        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(),
                FLAG_LOCK, testUserId);
        final WallpaperData systemWallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM,
                testUserId);
        final WallpaperData lockWallpaper = mService.getCurrentWallpaperData(FLAG_LOCK,
                testUserId);
        IWallpaperService mockIWallpaperService = mock(IWallpaperService.class);
        systemWallpaper.connection.mService = mockIWallpaperService;
        lockWallpaper.connection.mService = mockIWallpaperService;
        // GIVEN there are two displays: DEFAULT_DISPLAY, 2
        final int testDisplayId = 2;
        setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId));

        // WHEN displayId, 2, is ready.
        WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService(
                WallpaperManagerInternal.class);
        wallpaperManagerInternal.onDisplayReady(testDisplayId);

        // Then there is a connection established for the system wallpaper for display ID, 2.
        verify(mockIWallpaperService).attach(
                /* connection= */ eq(systemWallpaper.connection),
                /* windowToken= */ any(),
                /* windowType= */ anyInt(),
                /* isPreview= */ anyBoolean(),
                /* reqWidth= */ anyInt(),
                /* reqHeight= */ anyInt(),
                /* padding= */ any(),
                /* displayId= */ eq(testDisplayId),
                /* which= */ eq(FLAG_SYSTEM),
                /* info= */ any(),
                /* description= */ any());
        // Then there is a connection established for the lock wallpaper for display ID, 2.
        verify(mockIWallpaperService).attach(
                /* connection= */ eq(lockWallpaper.connection),
                /* windowToken= */ any(),
                /* windowType= */ anyInt(),
                /* isPreview= */ anyBoolean(),
                /* reqWidth= */ anyInt(),
                /* reqHeight= */ anyInt(),
                /* padding= */ any(),
                /* displayId= */ eq(testDisplayId),
                /* which= */ eq(FLAG_LOCK),
                /* info= */ any(),
                /* description= */ any());
    }
    // Verify a secondary display added end

    // Verify a secondary display removed started
    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER)
    public void displayRemoved_sameSystemAndLockWallpaper_shouldDetachWallpaperServiceOnce()
            throws Exception {
        ArgumentCaptor<DisplayListener> displayListenerCaptor = ArgumentCaptor.forClass(
                DisplayListener.class);
        verify(mDisplayManager).registerDisplayListener(displayListenerCaptor.capture(), eq(null));
        // GIVEN the same wallpaper used for the lock and system.
        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        final WallpaperData wallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM, testUserId);
        IWallpaperService mockIWallpaperService = mock(IWallpaperService.class);
        wallpaper.connection.mService = mockIWallpaperService;
        // GIVEN there are two displays: DEFAULT_DISPLAY, 2
        final int testDisplayId = 2;
        setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId));
        // GIVEN wallpaper connections have been established for displayID, 2.
        WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService(
                WallpaperManagerInternal.class);
        wallpaperManagerInternal.onDisplayReady(testDisplayId);
        // Save displayConnector for displayId 2 before display removal.
        WallpaperManagerService.DisplayConnector displayConnector =
                wallpaper.connection.getDisplayConnectorOrCreate(testDisplayId);

        // WHEN displayId, 2, is removed.
        DisplayListener displayListener = displayListenerCaptor.getValue();
        displayListener.onDisplayRemoved(testDisplayId);

        // Then the wallpaper connection for displayId, 2, is detached.
        verify(mockIWallpaperService).detach(eq(displayConnector.mToken));
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER)
    public void displayRemoved_differentSystemAndLockWallpapers_shouldDetachWallpaperServiceTwice()
            throws Exception {
        ArgumentCaptor<DisplayListener> displayListenerCaptor = ArgumentCaptor.forClass(
                DisplayListener.class);
        verify(mDisplayManager).registerDisplayListener(displayListenerCaptor.capture(), eq(null));
        // GIVEN different wallpapers used for the lock and system.
        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(),
                FLAG_LOCK, testUserId);
        final WallpaperData systemWallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM,
                testUserId);
        final WallpaperData lockWallpaper = mService.getCurrentWallpaperData(FLAG_LOCK,
                testUserId);
        IWallpaperService mockIWallpaperService = mock(IWallpaperService.class);
        systemWallpaper.connection.mService = mockIWallpaperService;
        lockWallpaper.connection.mService = mockIWallpaperService;
        // GIVEN there are two displays: DEFAULT_DISPLAY, 2
        final int testDisplayId = 2;
        setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId));
        // GIVEN wallpaper connections have been established for displayID, 2.
        WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService(
                WallpaperManagerInternal.class);
        wallpaperManagerInternal.onDisplayReady(testDisplayId);
        // Save displayConnectors for displayId 2 before display removal.
        WallpaperManagerService.DisplayConnector systemWallpaperDisplayConnector =
                systemWallpaper.connection.getDisplayConnectorOrCreate(testDisplayId);
        WallpaperManagerService.DisplayConnector lockWallpaperDisplayConnector =
                lockWallpaper.connection.getDisplayConnectorOrCreate(testDisplayId);

        // WHEN displayId, 2, is removed.
        DisplayListener displayListener = displayListenerCaptor.getValue();
        displayListener.onDisplayRemoved(testDisplayId);

        // Then the system wallpaper connection for displayId, 2, is detached.
        verify(mockIWallpaperService).detach(eq(systemWallpaperDisplayConnector.mToken));
        // Then the lock wallpaper connection for displayId, 2, is detached.
        verify(mockIWallpaperService).detach(eq(lockWallpaperDisplayConnector.mToken));
    }
    // Verify a secondary display removed ended

    // Verify that after continue switch user from userId 0 to lastUserId, the wallpaper data for
    // non-current user must not bind to wallpaper service.
    private void verifyNoConnectionBeforeLastUser(int lastUserId) {
@@ -681,11 +889,31 @@ public class WallpaperManagerServiceTests {
                lastData.connection);
    }

    private void verifyLastLockWallpaperData(int lastUserId, ComponentName expectedComponent) {
        final WallpaperData lastLockData = mService.mLastLockWallpaper;
        assertWithMessage("Last wallpaper must not be null").that(lastLockData).isNotNull();
        assertWithMessage("Last wallpaper component must be equals.")
                .that(expectedComponent)
                .isEqualTo(lastLockData.getComponent());
        assertWithMessage("The user id in last wallpaper should be the last switched user")
                .that(lastUserId)
                .isEqualTo(lastLockData.userId);
        assertWithMessage("Must exist user data connection on last wallpaper data")
                .that(lastLockData.connection)
                .isNotNull();
    }

    private void verifyCurrentSystemData(int userId) {
        final WallpaperData lastData = mService.mLastWallpaper;
        final WallpaperData wallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM, userId);
        assertEquals("Last wallpaper should be equals to current system wallpaper",
                lastData, wallpaper);

        final WallpaperData lastLockData = mService.mLastLockWallpaper;
        final WallpaperData lockWallpaper = mService.getCurrentWallpaperData(FLAG_LOCK, userId);
        assertWithMessage("Last lock wallpaper should be equals to current lock wallpaper")
                .that(lastLockData)
                .isEqualTo(lockWallpaper);
    }

    private void verifyDisplayData() {
@@ -697,6 +925,32 @@ public class WallpaperManagerServiceTests {
        });
    }

    /**
     * Sets up mock displays for testing.
     *
     * <p>This method creates mock {@link Display} objects and configures the {@link DisplayManager}
     * to return them. It also sets up the {@link WindowManagerInternal} to indicate that all
     * displays support home.
     *
     * @param displayIds A list of display IDs to create mock displays for.
     */
    private void setUpDisplays(List<Integer> displayIds) {
        doReturn(true).when(sWindowManagerInternal).isHomeSupportedOnDisplay(anyInt());

        Display[] mockDisplays = new Display[displayIds.size()];
        for (int i = 0; i < displayIds.size(); i++) {
            final int displayId = displayIds.get(i);
            final Display mockDisplay = mock(Display.class);
            mockDisplays[i] = mockDisplay;
            doReturn(DISPLAY_SIZE_DIMENSION).when(mockDisplay).getMaximumSizeDimension();
            doReturn(mockDisplay).when(mDisplayManager).getDisplay(eq(displayId));
            doReturn(displayId).when(mockDisplay).getDisplayId();
            doReturn(true).when(mockDisplay).hasAccess(anyInt());
        }

        doReturn(mockDisplays).when(mDisplayManager).getDisplays();
    }

    /**
     * Asserts that the contents of the given {@link ParcelFileDescriptor} and {@link File} contain
     * exactly the same bytes.