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

Commit 5553429a authored by Steven Ng's avatar Steven Ng
Browse files

Maintains fallback Wallpaper connections after set wallpaper

When setting a new wallpaper when the device is connected to multiple displays, fallback connections must be updated:
1. Remove connection: If the new wallpaper is compatible with displays that were previously incompatible.
2. Create connection: If the new wallpaper is incompatible with displays that were previously compatible.

Test: atests FrameworksMockingServicesTests:WallpaperManagerServiceTests
Flag: android.app.enable_connected_displays_wallpaper
Bug: 384520326
Change-Id: I097c1ab2ee718b6d83ed3e96fb81d0b8b0955053
parent f02e481a
Loading
Loading
Loading
Loading
+98 −14
Original line number Diff line number Diff line
@@ -781,13 +781,71 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        if (mLastWallpaper == null || mFallbackWallpaper == null) return;
        final WallpaperConnection systemConnection = mLastWallpaper.connection;
        final WallpaperConnection fallbackConnection = mFallbackWallpaper.connection;
        final WallpaperConnection lockConnection;
        if (mLastLockWallpaper != null) {
            lockConnection = mLastLockWallpaper.connection;
        } else {
            lockConnection = null;
        }
        if (fallbackConnection == null) {
            Slog.w(TAG, "Fallback wallpaper connection has not been created yet!!");
            return;
        }
        // TODO(b/384520326) Passing DEFAULT_DISPLAY temporarily before we revamp the
        //  multi-display supports.
        if (isWallpaperCompatibleForDisplay(DEFAULT_DISPLAY, systemConnection)) {

        if (enableConnectedDisplaysWallpaper()) {
            mWallpaperDisplayHelper.forEachDisplayData(displayData -> {
                int displayId = displayData.mDisplayId;
                // If the display is already connected to the desired wallpaper(s), either the
                // same wallpaper for both lock and system, or different wallpapers for each,
                // any existing fallback wallpaper connection will be removed.
                if (systemConnection.containsDisplay(displayId)
                        && (lockConnection == null || lockConnection.containsDisplay(displayId))) {
                    DisplayConnector fallbackConnector =
                            mFallbackWallpaper.connection.mDisplayConnector.get(displayId);
                    if (fallbackConnector != null && fallbackConnector.mEngine != null) {
                        fallbackConnector.disconnectLocked(mFallbackWallpaper.connection);
                        mFallbackWallpaper.connection.mDisplayConnector.remove(displayId);
                    }
                    return;
                }

                // Identify if the fallback wallpaper should be use for lock or system or both.
                int which = 0;
                if (!systemConnection.containsDisplay(displayId)) {
                    which |= FLAG_SYSTEM;
                }
                if (lockConnection == null || !lockConnection.containsDisplay(displayId)) {
                    which |= FLAG_LOCK;
                }
                if (mFallbackWallpaper.connection.containsDisplay(displayId)) {
                    // For existing fallback wallpaper connection, update the `which` flags.
                    DisplayConnector fallbackConnector =
                            mFallbackWallpaper.connection.mDisplayConnector.get(displayId);
                    try {
                        if (fallbackConnector != null && fallbackConnector.mEngine != null
                                && fallbackConnector.mWhich != which) {
                            fallbackConnector.mEngine.setWallpaperFlags(which);
                            mWindowManagerInternal.setWallpaperShowWhenLocked(
                                    fallbackConnector.mToken,
                                    /* showWhenLocked= */ (which & FLAG_LOCK) != 0);
                            fallbackConnector.mWhich = which;
                        }
                    } catch (RemoteException e) {
                        Slog.e(TAG, "Failed to update fallback wallpaper engine flags", e);
                    }
                } else {
                    // For new fallback connection, establish the connection with the desired
                    // `which` flag.
                    DisplayConnector fallbackConnector =
                            mFallbackWallpaper.connection.getDisplayConnectorOrCreate(displayId);
                    if (fallbackConnector != null && fallbackConnector.mEngine != null) {
                        fallbackConnector.mWhich = which;
                        fallbackConnector.connectLocked(mFallbackWallpaper.connection,
                                mFallbackWallpaper);
                    }
                }
            });
        } else if (isWallpaperCompatibleForDisplay(DEFAULT_DISPLAY, systemConnection)) {
            if (fallbackConnection.mDisplayConnector.size() != 0) {
                fallbackConnection.forEachDisplayConnector(connector -> {
                    if (connector.mEngine != null) {
@@ -820,8 +878,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        boolean mDimensionsChanged;
        boolean mPaddingChanged;

        DisplayConnector(int displayId) {
        // This field is added for the fallback wallpaper, which may have a different which flag for
        // a different display.
        int mWhich;

        DisplayConnector(int displayId, int which) {
            mDisplayId = displayId;
            mWhich = which;
        }

        void ensureStatusHandled() {
@@ -850,13 +913,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
                Slog.w(TAG, "WallpaperService is not connected yet");
                return;
            }
            int which = wallpaper.mWhich;
            if (enableConnectedDisplaysWallpaper()) {
                which = mWhich;
            }
            TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
            t.traceBegin("WPMS.connectLocked-" + wallpaper.getComponent());
            if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken);
            mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId,
                    null /* options */);
            mWindowManagerInternal.setWallpaperShowWhenLocked(
                    mToken, (wallpaper.mWhich & FLAG_LOCK) != 0);
                    mToken, (which & FLAG_LOCK) != 0);
            if (multiCrop() && mImageWallpaper.equals(wallpaper.getComponent())) {
                mWindowManagerInternal.setWallpaperCropHints(mToken,
                        mWallpaperCropper.getRelativeCropHints(wallpaper));
@@ -868,16 +935,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
            try {
                if (liveWallpaperContentHandling()) {
                    connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false,
                            wpdData.mWidth, wpdData.mHeight,
                            wpdData.mPadding, mDisplayId, wallpaper.mWhich, connection.mInfo,
                            wallpaper.getDescription());
                            wpdData.mWidth, wpdData.mHeight, wpdData.mPadding, mDisplayId, which,
                            connection.mInfo, wallpaper.getDescription());
                } else {
                    WallpaperDescription desc = new WallpaperDescription.Builder().setComponent(
                            (connection.mInfo != null) ? connection.mInfo.getComponent()
                                    : null).build();
                    connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false,
                            wpdData.mWidth, wpdData.mHeight,
                            wpdData.mPadding, mDisplayId, wallpaper.mWhich, connection.mInfo, desc);
                            wpdData.mWidth, wpdData.mHeight, wpdData.mPadding, mDisplayId, which,
                            connection.mInfo, desc);
                }
            } catch (RemoteException e) {
                Slog.w(TAG, "Failed attaching wallpaper on display", e);
@@ -980,7 +1046,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
                    final int displayId = display.getDisplayId();
                    final DisplayConnector connector = mDisplayConnector.get(displayId);
                    if (connector == null) {
                        mDisplayConnector.append(displayId, new DisplayConnector(displayId));
                        mDisplayConnector.append(displayId,
                                new DisplayConnector(displayId, mWallpaper.mWhich));
                    }
                }
            }
@@ -1006,7 +1073,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
            DisplayConnector connector = mDisplayConnector.get(displayId);
            if (connector == null) {
                if (mWallpaperDisplayHelper.isUsableDisplay(displayId, mClientUid)) {
                    connector = new DisplayConnector(displayId);
                    connector = new DisplayConnector(displayId, mWallpaper.mWhich);
                    mDisplayConnector.append(displayId, connector);
                }
            }
@@ -1364,6 +1431,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
                                Slog.v(TAG, "static system+lock to system failure");
                            }
                            WallpaperData currentSystem = mWallpaperMap.get(mNewWallpaper.userId);
                            // In the constructor, we copied the system+lock wallpaper to
                            // mOriginalSystem. However, the copied WallpaperData#connection is a
                            // reference, not a deep copy. This means
                            // currentSystem.connection.mWallpaper points to mOriginalSystem, so
                            // changes to currentSystem.mWhich alone won't update the corresponding
                            // flag in currentSystem.connection.mWallpaper.mWhich. Let's point
                            // currentSystem.connection.mWallpaper back to currentSystem.
                            if (enableConnectedDisplaysWallpaper()
                                    && currentSystem.connection != null) {
                                currentSystem.connection.mWallpaper = currentSystem;
                            }
                            currentSystem.mWhich = FLAG_SYSTEM | FLAG_LOCK;
                            updateEngineFlags(currentSystem);
                            mLockWallpaperMap.remove(mNewWallpaper.userId);
@@ -1385,6 +1463,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
                    }
                    WallpaperData currentSystem = mWallpaperMap.get(mNewWallpaper.userId);
                    if (currentSystem.wallpaperId == mOriginalSystem.wallpaperId) {
                        // Fixing the reference, see above for more details.
                        if (enableConnectedDisplaysWallpaper()
                                && currentSystem.connection != null) {
                            currentSystem.connection.mWallpaper = currentSystem;
                        }
                        currentSystem.mWhich = FLAG_SYSTEM;
                        updateEngineFlags(currentSystem);
                    }
@@ -3814,6 +3897,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        wallpaper.connection.forEachDisplayConnector(
                connector -> {
                    try {
                        connector.mWhich = wallpaper.mWhich;
                        if (connector.mEngine != null) {
                            connector.mEngine.setWallpaperFlags(wallpaper.mWhich);
                            mWindowManagerInternal.setWallpaperShowWhenLocked(
@@ -3949,8 +4033,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
            if (mLastWallpaper == null) {
                return;
            }
            if (enableConnectedDisplaysWallpaper()) {
            int useFallbackWallpaperWhich = 0;
            if (enableConnectedDisplaysWallpaper()) {
                List<WallpaperData> wallpapers = new ArrayList<>();
                wallpapers.add(mLastWallpaper);
                // If the system and the lock wallpapers are not the same, we should also
@@ -3981,7 +4065,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
                        || mFallbackWallpaper.connection == null) {
                    return;
                }
                mFallbackWallpaper.mWhich = useFallbackWallpaperWhich;
            } else {
                if (isWallpaperCompatibleForDisplay(displayId, mLastWallpaper.connection)) {
                    final DisplayConnector connector =
@@ -3999,6 +4082,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
                final DisplayConnector connector = mFallbackWallpaper
                        .connection.getDisplayConnectorOrCreate(displayId);
                if (connector == null) return;
                connector.mWhich = useFallbackWallpaperWhich;
                connector.connectLocked(mFallbackWallpaper.connection, mFallbackWallpaper);
            } else {
                Slog.w(TAG, "No wallpaper can be added to the new display");
+148 −0
Original line number Diff line number Diff line
@@ -1028,6 +1028,154 @@ public class WallpaperManagerServiceTests {
    }
    // Verify a secondary display removes system decorations ended

    // Test setWallpaperComponent on multiple displays.
    // GIVEN 3 displays, 0, 2, 3, the new wallpaper is only compatible for display 0 and 3 but not
    // 2.
    // WHEN the new wallpaper is set for system and lock via setWallpaperComponent.
    // THEN there are 2 connections in mLastWallpaper and 1 connection in mFallbackWallpaper.
    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER)
    public void setWallpaperComponent_multiDisplays_shouldHaveExpectedConnections() {
        // Skip if there is no pre-defined default wallpaper component.
        assumeThat(sDefaultWallpaperComponent,
                not(CoreMatchers.equalTo(sImageWallpaperComponentName)));

        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        final int incompatibleDisplayId = 2;
        final int compatibleDisplayId = 3;
        setUpDisplays(List.of(DEFAULT_DISPLAY, incompatibleDisplayId, compatibleDisplayId));
        mService.removeWallpaperCompatibleDisplayForTest(incompatibleDisplayId);

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

        verifyLastWallpaperData(testUserId, sImageWallpaperComponentName);
        verifyCurrentSystemData(testUserId);
        assertThat(mService.mLastWallpaper.connection.getConnectedEngineSize()).isEqualTo(2);
        assertThat(mService.mLastWallpaper.connection.containsDisplay(DEFAULT_DISPLAY)).isTrue();
        assertThat(mService.mLastWallpaper.connection.containsDisplay(compatibleDisplayId))
                .isTrue();
        assertThat(mService.mFallbackWallpaper.connection.getConnectedEngineSize()).isEqualTo(1);
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(incompatibleDisplayId))
                .isTrue();
        assertThat(mService.mLastLockWallpaper).isNull();
    }

    // Test setWallpaperComponent on multiple displays.
    // GIVEN 3 displays, 0, 2, 3, the existing wallpaper is only compatible for display 0 and 3 but
    // not 2.
    // GIVEN the new wallpaper is compatible to 2.
    // WHEN the new wallpaper is set for system and lock via setWallpaperComponent.
    // THEN there are 3 connections in mLastWallpaper and 0 connection in mFallbackWallpaper.
    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER)
    public void setWallpaperComponent_multiDisplays_displayBecomeCompatible_shouldHaveExpectedConnections() {
        // Skip if there is no pre-defined default wallpaper component.
        assumeThat(sDefaultWallpaperComponent,
                not(CoreMatchers.equalTo(sImageWallpaperComponentName)));

        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        final int display2 = 2;
        final int display3 = 3;
        setUpDisplays(List.of(DEFAULT_DISPLAY, display2, display3));
        mService.removeWallpaperCompatibleDisplayForTest(display2);
        mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(),
                FLAG_SYSTEM | FLAG_LOCK, testUserId);

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

        verifyLastWallpaperData(testUserId, sImageWallpaperComponentName);
        verifyCurrentSystemData(testUserId);
        assertThat(mService.mLastWallpaper.connection.getConnectedEngineSize()).isEqualTo(3);
        assertThat(mService.mLastWallpaper.connection.containsDisplay(DEFAULT_DISPLAY)).isTrue();
        assertThat(mService.mLastWallpaper.connection.containsDisplay(display2)).isTrue();
        assertThat(mService.mLastWallpaper.connection.containsDisplay(display3)).isTrue();
        assertThat(mService.mFallbackWallpaper.connection.getConnectedEngineSize()).isEqualTo(0);
        assertThat(mService.mLastLockWallpaper).isNull();
    }

    // Test setWallpaperComponent on multiple displays.
    // GIVEN 3 displays, 0, 2, 3, the existing wallpaper is only compatible for display 0 and 3 but
    // not 2.
    // GIVEN the new wallpaper is incompatible to 2 and 3.
    // WHEN the new wallpaper is set for system and lock via setWallpaperComponent.
    // THEN there are 1 connections in mLastWallpaper and 2 connection in mFallbackWallpaper.
    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER)
    public void setWallpaperComponent_multiDisplays_displayBecomeIncompatible_shouldHaveExpectedConnections() {
        // Skip if there is no pre-defined default wallpaper component.
        assumeThat(sDefaultWallpaperComponent,
                not(CoreMatchers.equalTo(sImageWallpaperComponentName)));

        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        final int display2 = 2;
        final int display3 = 3;
        setUpDisplays(List.of(DEFAULT_DISPLAY, display2, display3));
        mService.removeWallpaperCompatibleDisplayForTest(display2);
        mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(),
                FLAG_SYSTEM | FLAG_LOCK, testUserId);

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

        verifyLastWallpaperData(testUserId, sImageWallpaperComponentName);
        verifyCurrentSystemData(testUserId);
        assertThat(mService.mLastWallpaper.connection.getConnectedEngineSize()).isEqualTo(1);
        assertThat(mService.mLastWallpaper.connection.containsDisplay(DEFAULT_DISPLAY)).isTrue();
        assertThat(mService.mFallbackWallpaper.connection.getConnectedEngineSize()).isEqualTo(2);
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(display2)).isTrue();
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(display3)).isTrue();
        assertThat(mService.mLastLockWallpaper).isNull();
    }

    // Test setWallpaperComponent on multiple displays.
    // GIVEN 3 displays, 0, 2, 3, the new wallpaper is only compatible for display 0 and 3 but not
    // 2.
    // WHEN two different wallpapers set for system and lock via setWallpaperComponent.
    // THEN there are two connections in mLastWallpaper, two connection in mLastLockWallpaper and
    // one connection in mFallbackWallpaper.
    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER)
    public void setWallpaperComponent_systemAndLockWallpapers_multiDisplays_shouldHaveExpectedConnections() {
        // Skip if there is no pre-defined default wallpaper component.
        assumeThat(sDefaultWallpaperComponent,
                not(CoreMatchers.equalTo(sImageWallpaperComponentName)));

        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        final int incompatibleDisplayId = 2;
        final int compatibleDisplayId = 3;
        setUpDisplays(List.of(DEFAULT_DISPLAY, incompatibleDisplayId, compatibleDisplayId));
        mService.removeWallpaperCompatibleDisplayForTest(incompatibleDisplayId);

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

        verifyLastWallpaperData(testUserId, sImageWallpaperComponentName);
        verifyLastLockWallpaperData(testUserId, sImageWallpaperComponentName);
        verifyCurrentSystemData(testUserId);
        assertThat(mService.mLastWallpaper.connection.getConnectedEngineSize()).isEqualTo(2);
        assertThat(mService.mLastWallpaper.connection.containsDisplay(DEFAULT_DISPLAY)).isTrue();
        assertThat(mService.mLastWallpaper.connection.containsDisplay(compatibleDisplayId))
                .isTrue();
        assertThat(mService.mLastLockWallpaper.connection.getConnectedEngineSize()).isEqualTo(2);
        assertThat(mService.mLastLockWallpaper.connection.containsDisplay(DEFAULT_DISPLAY))
                .isTrue();
        assertThat(mService.mLastLockWallpaper.connection.containsDisplay(compatibleDisplayId))
                .isTrue();
        assertThat(mService.mFallbackWallpaper.connection.getConnectedEngineSize()).isEqualTo(1);
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(incompatibleDisplayId))
                .isTrue();
    }

    // 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) {