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

Commit 679e30ab authored by Steven Ng's avatar Steven Ng
Browse files

Fix fallback wallpaper connections after reboot

Issues:
1. After a reboot, fallback wallpaper connections are not established correctly because the DisplayData is created only after a display is connected.
2. Test issues:
    2.1: wrong assumption: tests previously added for fallback wallpaper connection tests for multi-displays are skipped. Remove these assumptions in this change.
    2.2: getConnectedEngineSize only returns the size of the display connectors that have a non-null engine. We don't stub the engine during these tests. Replaced this assertion with display connector display id assertions.
    2.3: added a TestWallpaperService to stimulate user changing wallpaper.

Test: atests FrameworksMockingServicesTests:WallpaperManagerServiceTests
Flag: android.app.enable_connected_displays_wallpaper
Bug: 384520326
Change-Id: Ic1368aa5d2045d5cf3ff5057e428ae4f7791df3e
parent 58f1298c
Loading
Loading
Loading
Loading
+14 −8
Original line number Diff line number Diff line
@@ -777,7 +777,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        mWallpaperCompatibleDisplaysForTest.remove(displayId);
    }

    private void updateFallbackConnection() {
    private void updateFallbackConnection(int clientUid) {
        if (mLastWallpaper == null || mFallbackWallpaper == null) return;
        final WallpaperConnection systemConnection = mLastWallpaper.connection;
        final WallpaperConnection fallbackConnection = mFallbackWallpaper.connection;
@@ -793,8 +793,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        }

        if (isDeviceEligibleForDesktopExperienceWallpaper(mContext)) {
            mWallpaperDisplayHelper.forEachDisplayData(displayData -> {
                int displayId = displayData.mDisplayId;
            Display[] displays = mWallpaperDisplayHelper.getDisplays();
            for (int i = displays.length - 1; i >= 0; i--) {
                int displayId = displays[i].getDisplayId();
                if (!mWallpaperDisplayHelper.isUsableDisplay(displayId, clientUid)) {
                    continue;
                }
                // 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.
@@ -802,11 +806,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
                        && (lockConnection == null || lockConnection.containsDisplay(displayId))) {
                    DisplayConnector fallbackConnector =
                            mFallbackWallpaper.connection.mDisplayConnector.get(displayId);
                    if (fallbackConnector != null && fallbackConnector.mEngine != null) {
                    if (fallbackConnector != null) {
                        if (fallbackConnector.mEngine != null) {
                            fallbackConnector.disconnectLocked(mFallbackWallpaper.connection);
                        }
                        mFallbackWallpaper.connection.mDisplayConnector.remove(displayId);
                    }
                    return;
                    continue;
                }

                // Identify if the fallback wallpaper should be use for lock or system or both.
@@ -844,7 +850,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
                                mFallbackWallpaper);
                    }
                }
            });
            }
        } else if (isWallpaperCompatibleForDisplay(DEFAULT_DISPLAY, systemConnection)) {
            if (fallbackConnection.mDisplayConnector.size() != 0) {
                fallbackConnection.forEachDisplayConnector(connector -> {
@@ -3787,7 +3793,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
            wallpaper.connection = newConn;
            newConn.mReply = reply;
            updateCurrentWallpapers(wallpaper);
            updateFallbackConnection();
            updateFallbackConnection(componentUid);
        } catch (RemoteException e) {
            String msg = "Remote exception for " + componentName + "\n" + e;
            if (fromUser) {
+10 −0
Original line number Diff line number Diff line
@@ -52,6 +52,16 @@
        <uses-library android:name="android.test.runner" />
        <activity
            android:name="android.service.games.GameSessionTrampolineActivityTest$TestActivity" />
        <service android:name="com.android.server.wallpaper.TestWallpaperService"
            android:label="Test Wallpaper Service"
            android:exported="true"
            android:permission="android.permission.BIND_WALLPAPER">
          <intent-filter>
            <action android:name="android.service.wallpaper.WallpaperService"/>
          </intent-filter>
          <meta-data android:name="android.service.wallpaper"
              android:resource="@xml/test_wallpaper"/>
        </service>
    </application>

    <instrumentation
+19 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  Copyright 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.
  -->
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="Test Wallpaper"
    android:supportsMultipleDisplays="true" />
+26 −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.server.wallpaper;

import android.service.wallpaper.WallpaperService;

public final class TestWallpaperService extends WallpaperService {
    @Override
    public Engine onCreateEngine() {
        return new Engine();
    }
}
+57 −47
Original line number Diff line number Diff line
@@ -136,6 +136,10 @@ public class WallpaperManagerServiceTests {

    private static final String TAG = "WallpaperManagerServiceTests";
    private static final int DISPLAY_SIZE_DIMENSION = 100;

    private static final ComponentName TEST_WALLPAPER_COMPONENT = ComponentName.createRelative(
            "com.android.frameworks.mockingservicestests",
            "com.android.server.wallpaper.TestWallpaperService");
    private static StaticMockitoSession sMockitoSession;

    @ClassRule
@@ -212,6 +216,7 @@ public class WallpaperManagerServiceTests {
        }

        sContext.addMockService(sImageWallpaperComponentName, sWallpaperService);
        sContext.addMockService(TEST_WALLPAPER_COMPONENT, sWallpaperService);
        if (sFallbackWallpaperComponentName != null) {
            sContext.addMockService(sFallbackWallpaperComponentName, sWallpaperService);
        }
@@ -1033,35 +1038,33 @@ 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.
    // Test fallback connection is correctly established for multiple displays after reboot.
    // GIVEN 3 displays, 0, 2, 3, the wallpaper is only compatible for display 0 and 3 but not 2.
    // WHEN the device is booted.
    // 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);
    public void deviceBooted_multiDisplays_shouldHaveExpectedConnections() {
        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);
        final int testUserId = USER_SYSTEM;
        // After reboot, a switch user triggers the wallpapers initialization.
        mService.switchUser(testUserId, null);

        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.mLastWallpaper.connection.containsDisplay(incompatibleDisplayId))
                .isFalse();
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(DEFAULT_DISPLAY))
                .isFalse();
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(compatibleDisplayId))
                .isFalse();
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(incompatibleDisplayId))
                .isTrue();
        assertThat(mService.mLastLockWallpaper).isNull();
@@ -1076,30 +1079,31 @@ public class WallpaperManagerServiceTests {
    @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(),
        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        // Switch to a test wallpaper and then image wallpaper later to simulate a wallpaper change.
        mService.setWallpaperComponent(TEST_WALLPAPER_COMPONENT, 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.mFallbackWallpaper.connection.containsDisplay(DEFAULT_DISPLAY)).isFalse();
        assertThat(
                mService.mFallbackWallpaper.connection.containsDisplay(display2)).isFalse();
        assertThat(
                mService.mFallbackWallpaper.connection.containsDisplay(display3)).isFalse();
        assertThat(mService.mLastLockWallpaper).isNull();
    }

@@ -1112,28 +1116,27 @@ public class WallpaperManagerServiceTests {
    @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(),
        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        // Switch to a test wallpaper and then image wallpaper later to simulate a wallpaper change.
        mService.setWallpaperComponent(TEST_WALLPAPER_COMPONENT, 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.mLastWallpaper.connection.containsDisplay(display2)).isFalse();
        assertThat(mService.mLastWallpaper.connection.containsDisplay(display3)).isFalse();
        assertThat(
                mService.mFallbackWallpaper.connection.containsDisplay(DEFAULT_DISPLAY)).isFalse();
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(display2)).isTrue();
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(display3)).isTrue();
        assertThat(mService.mLastLockWallpaper).isNull();
@@ -1148,35 +1151,40 @@ public class WallpaperManagerServiceTests {
    @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));
        final int testUserId = USER_SYSTEM;
        mService.switchUser(testUserId, null);
        // Switch to a test wallpaper and then image wallpaper later to simulate a wallpaper change.
        mService.setWallpaperComponent(TEST_WALLPAPER_COMPONENT, sContext.getOpPackageName(),
                FLAG_SYSTEM | FLAG_LOCK, testUserId);
        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);
        verifyLastLockWallpaperData(testUserId, TEST_WALLPAPER_COMPONENT);
        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.mLastWallpaper.connection.containsDisplay(incompatibleDisplayId))
                .isFalse();
        // mLastLockWallpaper is TEST_WALLPAPER_COMPONENT, which declares external displays support
        // in the wallpaper metadata.
        assertThat(mService.mLastLockWallpaper.connection.containsDisplay(DEFAULT_DISPLAY))
                .isTrue();
        assertThat(mService.mLastLockWallpaper.connection.containsDisplay(compatibleDisplayId))
                .isTrue();
        assertThat(mService.mFallbackWallpaper.connection.getConnectedEngineSize()).isEqualTo(1);
        assertThat(mService.mLastLockWallpaper.connection.containsDisplay(incompatibleDisplayId))
                .isTrue();
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(DEFAULT_DISPLAY))
                .isFalse();
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(compatibleDisplayId))
                .isFalse();
        assertThat(mService.mFallbackWallpaper.connection.containsDisplay(incompatibleDisplayId))
                .isTrue();
    }
@@ -1281,4 +1289,6 @@ public class WallpaperManagerServiceTests {
            assertEquals(pfdContents, fileContents);
        }
    }


}