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

Commit 7daaa9c9 authored by Chris Poultney's avatar Chris Poultney
Browse files

Add content handling support to B&R

Fixes: 376172272
Flag: android.app.live_wallpaper_content_handling
Test: manually verified correct B&R with flag enabled and disabled
Change-Id: I752d4efa724a039af433820794e5159dbaec440a
parent e1fcbf1f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -48,7 +48,9 @@ android_test {
    static_libs: [
        "androidx.test.core",
        "androidx.test.rules",
        "flag-junit",
        "mockito-target-minus-junit4",
        "platform-test-annotations",
        "truth",
    ],
    resource_dirs: ["test/res"],
+97 −27
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.wallpaperbackup;

import static android.app.Flags.liveWallpaperContentHandling;
import static android.app.WallpaperManager.FLAG_LOCK;
import static android.app.WallpaperManager.FLAG_SYSTEM;
import static android.app.WallpaperManager.ORIENTATION_UNKNOWN;
@@ -27,6 +28,7 @@ import static com.android.wallpaperbackup.WallpaperEventLogger.ERROR_NO_WALLPAPE
import static com.android.wallpaperbackup.WallpaperEventLogger.ERROR_QUOTA_EXCEEDED;
import static com.android.window.flags.Flags.multiCrop;

import android.annotation.Nullable;
import android.app.AppGlobals;
import android.app.WallpaperManager;
import android.app.backup.BackupAgent;
@@ -35,6 +37,7 @@ import android.app.backup.BackupDataOutput;
import android.app.backup.BackupManager;
import android.app.backup.BackupRestoreEventLogger.BackupRestoreError;
import android.app.backup.FullBackupDataOutput;
import android.app.wallpaper.WallpaperDescription;
import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
@@ -493,11 +496,13 @@ public class WallpaperBackupAgent extends BackupAgent {

            // First parse the live component name so that we know for logging if we care about
            // logging errors with the image restore.
            ComponentName wpService = parseWallpaperComponent(infoStage, "wp");
            mSystemHasLiveComponent = wpService != null;
            Pair<ComponentName, WallpaperDescription> wpService = parseWallpaperComponent(infoStage,
                    "wp");
            mSystemHasLiveComponent = wpService.first != null;

            ComponentName kwpService = parseWallpaperComponent(infoStage, "kwp");
            mLockHasLiveComponent = kwpService != null;
            Pair<ComponentName, WallpaperDescription> kwpService = parseWallpaperComponent(
                    infoStage, "kwp");
            mLockHasLiveComponent = kwpService.first != null;
            boolean separateLockWallpaper = mLockHasLiveComponent || lockImageStage.exists();

            // if there's no separate lock wallpaper, apply the system wallpaper to both screens.
@@ -586,25 +591,39 @@ public class WallpaperBackupAgent extends BackupAgent {
    }

    @VisibleForTesting
    void updateWallpaperComponent(ComponentName wpService, int which)
    void updateWallpaperComponent(Pair<ComponentName, WallpaperDescription> wpService, int which)
            throws IOException {
        if (servicePackageExists(wpService)) {
            Slog.i(TAG, "Using wallpaper service " + wpService);
            mWallpaperManager.setWallpaperComponentWithFlags(wpService, which);
        WallpaperDescription description = wpService.second;
        boolean hasDescription = (liveWallpaperContentHandling() && description != null);
        ComponentName component = hasDescription ? description.getComponent() : wpService.first;
        if (servicePackageExists(component)) {
            if (hasDescription) {
                Slog.i(TAG, "Using wallpaper description " + description);
                mWallpaperManager.setWallpaperComponentWithDescription(description, which);
                if ((which & FLAG_LOCK) != 0) {
                mEventLogger.onLockLiveWallpaperRestored(wpService);
                    mEventLogger.onLockLiveWallpaperRestoredWithDescription(description);
                }
                if ((which & FLAG_SYSTEM) != 0) {
                mEventLogger.onSystemLiveWallpaperRestored(wpService);
                    mEventLogger.onSystemLiveWallpaperRestoredWithDescription(description);
                }
            } else {
                Slog.i(TAG, "Using wallpaper service " + component);
                mWallpaperManager.setWallpaperComponentWithFlags(component, which);
                if ((which & FLAG_LOCK) != 0) {
                    mEventLogger.onLockLiveWallpaperRestored(component);
                }
                if ((which & FLAG_SYSTEM) != 0) {
                    mEventLogger.onSystemLiveWallpaperRestored(component);
                }
            }
        } else {
            // If we've restored a live wallpaper, but the component doesn't exist,
            // we should log it as an error so we can easily identify the problem
            // in reports from users
            if (wpService != null) {
            if (component != null) {
                // TODO(b/268471749): Handle delayed case
                applyComponentAtInstall(wpService, which);
                Slog.w(TAG, "Wallpaper service " + wpService + " isn't available. "
                applyComponentAtInstall(component, description, which);
                Slog.w(TAG, "Wallpaper service " + component + " isn't available. "
                        + " Will try to apply later");
            }
        }
@@ -697,7 +716,6 @@ public class WallpaperBackupAgent extends BackupAgent {
     * (thereby preserving the center point). Then finally, adding any leftover image real-estate
     * (i.e. space left over on the horizontal axis) to add parallax effect. Parallax is only added
     * if was present in the old device's settings.
     *
     */
    private Rect findNewCropfromOldCrop(Rect oldCrop, Point oldDisplaySize, boolean oldRtl,
            Point newDisplaySize, Point bitmapSize, boolean newRtl) {
@@ -976,10 +994,12 @@ public class WallpaperBackupAgent extends BackupAgent {
        return cropHints;
    }

    private ComponentName parseWallpaperComponent(File wallpaperInfo, String sectionTag) {
    private Pair<ComponentName, WallpaperDescription> parseWallpaperComponent(File wallpaperInfo,
            String sectionTag) {
        ComponentName name = null;
        WallpaperDescription description = null;
        try (FileInputStream stream = new FileInputStream(wallpaperInfo)) {
            final XmlPullParser parser = Xml.resolvePullParser(stream);
            final TypedXmlPullParser parser = Xml.resolvePullParser(stream);

            int type;
            do {
@@ -991,6 +1011,7 @@ public class WallpaperBackupAgent extends BackupAgent {
                        name = (parsedName != null)
                                ? ComponentName.unflattenFromString(parsedName)
                                : null;
                        description = parseWallpaperDescription(parser, name);
                        break;
                    }
                }
@@ -998,9 +1019,30 @@ public class WallpaperBackupAgent extends BackupAgent {
        } catch (Exception e) {
            // Whoops; can't process the info file at all.  Report failure.
            Slog.w(TAG, "Failed to parse restored component: " + e.getMessage());
            return null;
            return new Pair<>(null, null);
        }
        return name;
        return new Pair<>(name, description);
    }

    // Copied from com.android.server.wallpaper.WallpaperDataParser
    private WallpaperDescription parseWallpaperDescription(TypedXmlPullParser parser,
            ComponentName component) throws XmlPullParserException, IOException {

        WallpaperDescription description = null;
        int type = parser.next();
        if (type == XmlPullParser.START_TAG && "description".equals(parser.getName())) {
            // Always read the description if it's there - there may be one from a previous save
            // with content handling enabled even if it's enabled now
            description = WallpaperDescription.restoreFromXml(parser);
            if (liveWallpaperContentHandling()) {
                // null component means that wallpaper was last saved without content handling, so
                // populate description from saved component
                if (description.getComponent() == null) {
                    description = description.toBuilder().setComponent(component).build();
                }
            }
        }
        return description;
    }

    private int getAttributeInt(XmlPullParser parser, String name, int defValue) {
@@ -1037,14 +1079,16 @@ public class WallpaperBackupAgent extends BackupAgent {
        // Intentionally blank
    }

    private void applyComponentAtInstall(ComponentName componentName, int which) {
        PackageMonitor packageMonitor = getWallpaperPackageMonitor(
                componentName, which);
    private void applyComponentAtInstall(ComponentName componentName,
            @Nullable WallpaperDescription description, int which) {
        PackageMonitor packageMonitor = getWallpaperPackageMonitor(componentName, description,
                which);
        packageMonitor.register(getBaseContext(), null, UserHandle.ALL, true);
    }

    @VisibleForTesting
    PackageMonitor getWallpaperPackageMonitor(ComponentName componentName, int which) {
    PackageMonitor getWallpaperPackageMonitor(ComponentName componentName,
            @Nullable WallpaperDescription description, int which) {
        return new PackageMonitor() {
            @Override
            public void onPackageAdded(String packageName, int uid) {
@@ -1068,7 +1112,33 @@ public class WallpaperBackupAgent extends BackupAgent {
                    return;
                }

                if (componentName.getPackageName().equals(packageName)) {
                boolean useDescription = (liveWallpaperContentHandling() && description != null
                        && description.getComponent() != null);
                if (useDescription && description.getComponent().getPackageName().equals(
                        packageName)) {
                    Slog.d(TAG, "Applying description " + description);
                    boolean success = mWallpaperManager.setWallpaperComponentWithDescription(
                            description, which);
                    WallpaperEventLogger logger = new WallpaperEventLogger(
                            mBackupManager.getDelayedRestoreLogger());
                    if (success) {
                        if ((which & FLAG_SYSTEM) != 0) {
                            logger.onSystemLiveWallpaperRestoredWithDescription(description);
                        }
                        if ((which & FLAG_LOCK) != 0) {
                            logger.onLockLiveWallpaperRestoredWithDescription(description);
                        }
                    } else {
                        if ((which & FLAG_SYSTEM) != 0) {
                            logger.onSystemLiveWallpaperRestoreFailed(
                                    WallpaperEventLogger.ERROR_SET_DESCRIPTION_EXCEPTION);
                        }
                        if ((which & FLAG_LOCK) != 0) {
                            logger.onLockLiveWallpaperRestoreFailed(
                                    WallpaperEventLogger.ERROR_SET_DESCRIPTION_EXCEPTION);
                        }
                    }
                } else if (componentName.getPackageName().equals(packageName)) {
                    Slog.d(TAG, "Applying component " + componentName);
                    boolean success = mWallpaperManager.setWallpaperComponentWithFlags(
                            componentName, which);
+43 −6
Original line number Diff line number Diff line
@@ -16,12 +16,14 @@

package com.android.wallpaperbackup;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WallpaperInfo;
import android.app.backup.BackupManager;
import android.app.backup.BackupRestoreEventLogger;
import android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType;
import android.app.backup.BackupRestoreEventLogger.BackupRestoreError;
import android.app.wallpaper.WallpaperDescription;
import android.content.ComponentName;

import com.android.internal.annotations.VisibleForTesting;
@@ -53,6 +55,16 @@ public class WallpaperEventLogger {
    @VisibleForTesting
    static final String WALLPAPER_LIVE_LOCK = "wlp_live_lock";

    /* Live component used as system (or home) screen wallpaper */
    @BackupRestoreDataType
    @VisibleForTesting
    static final String WALLPAPER_DESCRIPTION_SYSTEM = "wlp_description_system";

    /* Live component used as lock screen wallpaper */
    @BackupRestoreDataType
    @VisibleForTesting
    static final String WALLPAPER_DESCRIPTION_LOCK = "wlp_description_lock";

    @BackupRestoreError
    static final String ERROR_INELIGIBLE = "ineligible";
    @BackupRestoreError
@@ -64,6 +76,8 @@ public class WallpaperEventLogger {
    @BackupRestoreError
    static final String ERROR_SET_COMPONENT_EXCEPTION = "exception_in_set_component";
    @BackupRestoreError
    static final String ERROR_SET_DESCRIPTION_EXCEPTION = "exception_in_set_description";
    @BackupRestoreError
    static final String ERROR_LIVE_PACKAGE_NOT_INSTALLED = "live_pkg_not_installed_in_restore";

    private final BackupRestoreEventLogger mLogger;
@@ -115,11 +129,11 @@ public class WallpaperEventLogger {
    }

    void onSystemImageWallpaperRestored() {
        logRestoreSuccessInternal(WALLPAPER_IMG_SYSTEM, /* liveComponentWallpaperInfo */ null);
        logRestoreSuccessInternal(WALLPAPER_IMG_SYSTEM, (ComponentName) null);
    }

    void onLockImageWallpaperRestored() {
        logRestoreSuccessInternal(WALLPAPER_IMG_LOCK, /* liveComponentWallpaperInfo */ null);
        logRestoreSuccessInternal(WALLPAPER_IMG_LOCK, (ComponentName) null);
    }

    void onSystemLiveWallpaperRestored(ComponentName wpService) {
@@ -146,6 +160,13 @@ public class WallpaperEventLogger {
        logRestoreFailureInternal(WALLPAPER_LIVE_LOCK, error);
    }

    void onSystemLiveWallpaperRestoredWithDescription(@NonNull WallpaperDescription description) {
        logRestoreSuccessInternal(WALLPAPER_DESCRIPTION_SYSTEM, description);
    }

    void onLockLiveWallpaperRestoredWithDescription(@NonNull WallpaperDescription description) {
        logRestoreSuccessInternal(WALLPAPER_DESCRIPTION_LOCK, description);
    }


    /**
@@ -168,15 +189,17 @@ public class WallpaperEventLogger {
     */
    void onRestoreException(Exception exception) {
        String error = exception.getClass().getName();
        if (!mProcessedDataTypes.contains(WALLPAPER_IMG_SYSTEM) && !mProcessedDataTypes.contains(
                WALLPAPER_LIVE_SYSTEM)) {
        if (!(mProcessedDataTypes.contains(WALLPAPER_IMG_SYSTEM) || mProcessedDataTypes.contains(
                WALLPAPER_LIVE_SYSTEM) || mProcessedDataTypes.contains(
                WALLPAPER_DESCRIPTION_SYSTEM))) {
            mLogger.logItemsRestoreFailed(WALLPAPER_IMG_SYSTEM, /* count */ 1, error);
        }
        if (!mProcessedDataTypes.contains(WALLPAPER_IMG_LOCK) && !mProcessedDataTypes.contains(
                WALLPAPER_LIVE_LOCK)) {
        if (!(mProcessedDataTypes.contains(WALLPAPER_IMG_LOCK) || mProcessedDataTypes.contains(
                WALLPAPER_LIVE_LOCK) || mProcessedDataTypes.contains(WALLPAPER_DESCRIPTION_LOCK))) {
            mLogger.logItemsRestoreFailed(WALLPAPER_IMG_LOCK, /* count */ 1, error);
        }
    }

    private void logBackupSuccessInternal(@BackupRestoreDataType String which,
            @Nullable WallpaperInfo liveComponentWallpaperInfo) {
        mLogger.logItemsBackedUp(which, /* count */ 1);
@@ -197,6 +220,13 @@ public class WallpaperEventLogger {
        mProcessedDataTypes.add(which);
    }

    private void logRestoreSuccessInternal(@BackupRestoreDataType String which,
            @NonNull WallpaperDescription description) {
        mLogger.logItemsRestored(which, /* count */ 1);
        logRestoredLiveWallpaperDescription(which, description);
        mProcessedDataTypes.add(which);
    }

    private void logRestoreFailureInternal(@BackupRestoreDataType String which,
            @BackupRestoreError String error) {
        mLogger.logItemsRestoreFailed(which, /* count */ 1, error);
@@ -216,4 +246,11 @@ public class WallpaperEventLogger {
            mLogger.logRestoreMetadata(wallpaperType, wpService.getClassName());
        }
    }

    private void logRestoredLiveWallpaperDescription(@BackupRestoreDataType String wallpaperType,
            WallpaperDescription description) {
        if (description != null) {
            mLogger.logRestoreMetadata(wallpaperType, description.toString());
        }
    }
}
+160 −14

File changed.

Preview size limit exceeded, changes collapsed.

+88 −2
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.wallpaperbackup;

import static android.app.Flags.FLAG_LIVE_WALLPAPER_CONTENT_HANDLING;

import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_DESCRIPTION_LOCK;
import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_DESCRIPTION_SYSTEM;
import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_IMG_LOCK;
import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_IMG_SYSTEM;
import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_LIVE_LOCK;
@@ -31,16 +35,20 @@ import android.app.WallpaperInfo;
import android.app.backup.BackupAnnotations;
import android.app.backup.BackupManager;
import android.app.backup.BackupRestoreEventLogger;
import android.app.wallpaper.WallpaperDescription;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.wallpaper.WallpaperService;

import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -63,6 +71,10 @@ public class WallpaperEventLoggerTest {

    private WallpaperEventLogger mWallpaperEventLogger;
    private WallpaperInfo mWallpaperInfo;
    private WallpaperDescription mWallpaperDescription;

    @Rule
    public SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    @Before
    public void setUp() throws Exception {
@@ -73,6 +85,8 @@ public class WallpaperEventLoggerTest {

        mWallpaperInfo = getWallpaperInfo();
        mWallpaperEventLogger = new WallpaperEventLogger(mMockBackupManager, mMockBackupAgent);
        mWallpaperDescription = new WallpaperDescription.Builder().setComponent(
                mWallpaperInfo.getComponent()).build();
    }

    @Test
@@ -262,6 +276,19 @@ public class WallpaperEventLoggerTest {
        assertThat(result.getSuccessCount()).isEqualTo(1);
    }

    @Test
    @EnableFlags(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING)
    public void onSystemLiveWallpaperRestoredWithDescription_logsSuccess() {
        setUpLoggerForRestore();

        mWallpaperEventLogger.onSystemLiveWallpaperRestoredWithDescription(mWallpaperDescription);
        BackupRestoreEventLogger.DataTypeResult result = getLogsForType(
                WALLPAPER_DESCRIPTION_SYSTEM);

        assertThat(result).isNotNull();
        assertThat(result.getSuccessCount()).isEqualTo(1);
    }

    @Test
    public void onLockLiveWallpaperRestored_logsSuccess() {
        setUpLoggerForRestore();
@@ -273,6 +300,17 @@ public class WallpaperEventLoggerTest {
        assertThat(result.getSuccessCount()).isEqualTo(1);
    }

    @Test
    public void onLockLiveWallpaperRestoredWithDescription_logsSuccess() {
        setUpLoggerForRestore();

        mWallpaperEventLogger.onLockLiveWallpaperRestoredWithDescription(mWallpaperDescription);
        BackupRestoreEventLogger.DataTypeResult result = getLogsForType(WALLPAPER_DESCRIPTION_LOCK);

        assertThat(result).isNotNull();
        assertThat(result.getSuccessCount()).isEqualTo(1);
    }

    @Test
    public void onImgWallpaperRestored_nullInfo_doesNotLogMetadata() {
        setUpLoggerForRestore();
@@ -286,7 +324,7 @@ public class WallpaperEventLoggerTest {


    @Test
    public void onLiveWallpaperRestored_logsMetadata() {
    public void onSystemLiveWallpaperRestored_logsMetadata() {
        setUpLoggerForRestore();

        mWallpaperEventLogger.onSystemLiveWallpaperRestored(mWallpaperInfo.getComponent());
@@ -296,6 +334,19 @@ public class WallpaperEventLoggerTest {
        assertThat(result.getMetadataHash()).isNotNull();
    }

    @Test
    @EnableFlags(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING)
    public void onSystemLiveWallpaperRestoredDescription_logsMetadata() {
        setUpLoggerForRestore();

        mWallpaperEventLogger.onSystemLiveWallpaperRestoredWithDescription(mWallpaperDescription);
        BackupRestoreEventLogger.DataTypeResult result = getLogsForType(
                WALLPAPER_DESCRIPTION_SYSTEM);

        assertThat(result).isNotNull();
        assertThat(result.getMetadataHash()).isNotNull();
    }


    @Test
    public void onSystemImgWallpaperRestoreFailed_logsFail() {
@@ -373,7 +424,7 @@ public class WallpaperEventLoggerTest {
    }

    @Test
    public void onWallpaperRestoreException_liveTypeProcessed_doesNotLogForSameImgType() {
    public void onSystemWallpaperRestoreException_liveTypeProcessed_doesNotLogForSameImgType() {
        setUpLoggerForRestore();
        mWallpaperEventLogger.onSystemLiveWallpaperRestored(mWallpaperInfo.getComponent());

@@ -383,6 +434,41 @@ public class WallpaperEventLoggerTest {
        assertThat(result).isNull();
    }

    @Test
    @EnableFlags(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING)
    public void onSystemWallpaperRestoreException_descriptionProcessed_doesNotLogForSameImgType() {
        setUpLoggerForRestore();
        mWallpaperEventLogger.onSystemLiveWallpaperRestoredWithDescription(mWallpaperDescription);

        mWallpaperEventLogger.onRestoreException(new Exception());
        BackupRestoreEventLogger.DataTypeResult result = getLogsForType(WALLPAPER_IMG_SYSTEM);

        assertThat(result).isNull();
    }

    @Test
    public void onLockWallpaperRestoreException_liveTypeProcessed_doesNotLogForSameImgType() {
        setUpLoggerForRestore();
        mWallpaperEventLogger.onLockLiveWallpaperRestored(mWallpaperInfo.getComponent());

        mWallpaperEventLogger.onRestoreException(new Exception());
        BackupRestoreEventLogger.DataTypeResult result = getLogsForType(WALLPAPER_IMG_LOCK);

        assertThat(result).isNull();
    }

    @Test
    @EnableFlags(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING)
    public void onLockWallpaperRestoreException_descriptionProcessed_doesNotLogForSameImgType() {
        setUpLoggerForRestore();
        mWallpaperEventLogger.onLockLiveWallpaperRestoredWithDescription(mWallpaperDescription);

        mWallpaperEventLogger.onRestoreException(new Exception());
        BackupRestoreEventLogger.DataTypeResult result = getLogsForType(WALLPAPER_IMG_LOCK);

        assertThat(result).isNull();
    }

    private BackupRestoreEventLogger.DataTypeResult getLogsForType(String dataType) {
        for (BackupRestoreEventLogger.DataTypeResult result :  mEventLogger.getLoggingResults()) {
            if ((result.getDataType()).equals(dataType)) {