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

Commit a5dc9ce0 authored by Aurélien Pomini's avatar Aurélien Pomini
Browse files

Strengthen Wallpaper clear logic

The changes are (all under flag):
 - support calling clearWallpaperLocked(FLAG_LOCK | FLAG_SYSTEM), which
   can be done more efficiently than clear(FLAG_LOCK) then
   clear(FLAG_SYSTEM).
 - add a check INTERACT_ACROSS_USER_FULL instead of returning if
clear is called for another userId than mCurrentUserId
 - use setWallpaperComponent and not bindWallpaperComponentLocked in
   clear, since setWallpaperComponent does other important things that
   we need when changing wallpapers. This is the most important change.

Also amend the javadoc to clarify the clear behaviour.

Flag: lock screen lwp
Bug: 283091821
Test: atest WallpaperManagerTest
Test: manual: disable security checks, then for all possible
combinations of static/live wallpaper(s), run:
"adb shell service call wallpaper 10 s16 "test" i32 X i32 0"
for X in (1, 2, 3) (resp. system, lock, system | lock)

Change-Id: I86a9f18a1d236633e4de3923861a5b55c7c4c996
parent 8b5a88fd
Loading
Loading
Loading
Loading
+33 −7
Original line number Diff line number Diff line
@@ -2476,19 +2476,38 @@ public class WallpaperManager {
    }

    /**
     * Reset all wallpaper to the factory default.
     * Reset all wallpaper to the factory default. As opposed to {@link #clear()}, if the device
     * is configured to have a live wallpaper by default, apply it.
     *
     * <p>This method requires the caller to hold the permission
     * {@link android.Manifest.permission#SET_WALLPAPER}.
     */
    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
    public void clearWallpaper() {
        if (isLockscreenLiveWallpaperEnabled()) {
            clearWallpaper(FLAG_LOCK | FLAG_SYSTEM, mContext.getUserId());
            return;
        }
        clearWallpaper(FLAG_LOCK, mContext.getUserId());
        clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
    }

    /**
     * Clear the wallpaper for a specific user.  The caller must hold the
     * Clear the wallpaper for a specific user.
     * <ul>
     *     <li> When called with {@code which=}{@link #FLAG_LOCK}, clear the lockscreen wallpaper.
     *     The home screen wallpaper will become visible on the lock screen. </li>
     *
     *     <li> When called with {@code which=}{@link #FLAG_SYSTEM}, revert the home screen
     *     wallpaper to default. The lockscreen wallpaper will be unchanged: if the previous
     *     wallpaper was shared between home and lock screen, it will become lock screen only. </li>
     *
     *     <li> When called with {@code which=}({@link #FLAG_LOCK} | {@link #FLAG_SYSTEM}), put the
     *     default wallpaper on both home and lock screen, removing any user defined wallpaper.</li>
     * </ul>
     * </p>
     *
     * The caller must hold the
     * INTERACT_ACROSS_USERS_FULL permission to clear another user's
     * wallpaper, and must hold the SET_WALLPAPER permission in all
     * circumstances.
@@ -2793,8 +2812,9 @@ public class WallpaperManager {

    /**
     * Remove any currently set system wallpaper, reverting to the system's built-in
     * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
     * is broadcast.
     * wallpaper. As opposed to {@link #clearWallpaper()}, this method always set a static wallpaper
     * with the default image, even if the device is configured to have a live wallpaper by default.
     * On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
     *
     * <p>This method requires the caller to hold the permission
     * {@link android.Manifest.permission#SET_WALLPAPER}.
@@ -2809,9 +2829,14 @@ public class WallpaperManager {

    /**
     * Remove one or more currently set wallpapers, reverting to the system default
     * display for each one.  If {@link #FLAG_SYSTEM} is set in the {@code which}
     * parameter, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} will be broadcast
     * upon success.
     * display for each one. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
     * is broadcast.
     * <ul>
     *     <li> If {@link #FLAG_SYSTEM} is set in the {@code which} parameter, put the default
     *     wallpaper on both home and lock screen, removing any user defined wallpaper. </li>
     *     <li> When called with {@code which=}{@link #FLAG_LOCK}, clear the lockscreen wallpaper.
     *     The home screen wallpaper will become visible on the lock screen. </li>
     * </ul>
     *
     * @param which A bitwise combination of {@link #FLAG_SYSTEM} or
     *   {@link #FLAG_LOCK}
@@ -2821,6 +2846,7 @@ public class WallpaperManager {
    public void clear(@SetWallpaperFlags int which) throws IOException {
        if ((which & FLAG_SYSTEM) != 0) {
            clear();
            if (isLockscreenLiveWallpaperEnabled()) return;
        }
        if ((which & FLAG_LOCK) != 0) {
            clearWallpaper(FLAG_LOCK, mContext.getUserId());
+77 −8
Original line number Diff line number Diff line
@@ -1991,7 +1991,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub

        WallpaperData data = null;
        synchronized (mLock) {
            if (mIsLockscreenLiveWallpaperEnabled) {
                clearWallpaperLocked(callingPackage, false, which, userId);
            } else {
                clearWallpaperLocked(false, which, userId, null);
            }

            if (which == FLAG_LOCK) {
                data = mLockWallpaperMap.get(userId);
@@ -2008,7 +2012,64 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        }
    }

    void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
    private void clearWallpaperLocked(String callingPackage, boolean defaultFailed,
            int which, int userId) {

        // Might need to bring it in the first time to establish our rewrite
        if (!mWallpaperMap.contains(userId)) {
            loadSettingsLocked(userId, false, FLAG_LOCK | FLAG_SYSTEM);
        }
        final WallpaperData wallpaper = mWallpaperMap.get(userId);
        final WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
        if (which == FLAG_LOCK && lockWallpaper == null) {
            // It's already gone; we're done.
            if (DEBUG) {
                Slog.i(TAG, "Lock wallpaper already cleared");
            }
            return;
        }

        RuntimeException e = null;
        try {
            if (userId != mCurrentUserId && !hasCrossUserPermission()) return;

            final ComponentName component;
            final int finalWhich;

            if ((which & FLAG_LOCK) > 0 && lockWallpaper != null) {
                clearWallpaperBitmaps(lockWallpaper);
            }
            if ((which & FLAG_SYSTEM) > 0) {
                clearWallpaperBitmaps(wallpaper);
            }

            // lock only case: set the system wallpaper component to both screens
            if (which == FLAG_LOCK) {
                component = wallpaper.wallpaperComponent;
                finalWhich = FLAG_LOCK | FLAG_SYSTEM;
            } else {
                component = defaultFailed ? mImageWallpaper : null;
                finalWhich = which;
            }

            boolean success = withCleanCallingIdentity(() -> setWallpaperComponent(
                    component, callingPackage, finalWhich, userId));
            if (success) return;
        } catch (IllegalArgumentException e1) {
            e = e1;
        }

        // This can happen if the default wallpaper component doesn't
        // exist. This should be a system configuration problem, but
        // let's not let it crash the system and just live with no
        // wallpaper.
        Slog.e(TAG, "Default wallpaper component not found!", e);
        withCleanCallingIdentity(() -> clearWallpaperComponentLocked(wallpaper));
    }

    // TODO(b/266818039) remove this version of the method
    private void clearWallpaperLocked(boolean defaultFailed, int which, int userId,
            IRemoteCallback reply) {
        if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
            throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear");
        }
@@ -3099,8 +3160,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub

        // Migrate the bitmap files outright; no need to copy
        try {
            Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath());
            if (!mIsLockscreenLiveWallpaperEnabled || sysWP.wallpaperFile.exists()) {
                Os.rename(sysWP.wallpaperFile.getAbsolutePath(),
                        lockWP.wallpaperFile.getAbsolutePath());
            }
            if (!mIsLockscreenLiveWallpaperEnabled || sysWP.cropFile.exists()) {
                Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath());
            }
            mLockWallpaperMap.put(userId, lockWP);
            if (mIsLockscreenLiveWallpaperEnabled) {
                SELinux.restorecon(lockWP.wallpaperFile);
@@ -3163,16 +3229,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
    }

    @VisibleForTesting
    void setWallpaperComponent(ComponentName name, String callingPackage,
    boolean setWallpaperComponent(ComponentName name, String callingPackage,
            @SetWallpaperFlags int which, int userId) {
        if (mIsLockscreenLiveWallpaperEnabled) {
            setWallpaperComponentInternal(name, callingPackage, which, userId);
            return setWallpaperComponentInternal(name, callingPackage, which, userId);
        } else {
            setWallpaperComponentInternalLegacy(name, callingPackage, which, userId);
            return true;
        }
    }

    private void setWallpaperComponentInternal(ComponentName name, String callingPackage,
    private boolean setWallpaperComponentInternal(ComponentName name, String callingPackage,
            @SetWallpaperFlags int which, int userIdIn) {
        if (DEBUG) {
            Slog.v(TAG, "Setting new live wallpaper: which=" + which + ", component: " + name);
@@ -3183,6 +3250,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);

        boolean shouldNotifyColors = false;
        boolean bindSuccess;
        final WallpaperData newWallpaper;

        synchronized (mLock) {
@@ -3231,7 +3299,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
                 */
                boolean forceRebind = same && systemIsBoth && which == FLAG_SYSTEM;

                boolean bindSuccess = bindWallpaperComponentLocked(name, /* force */
                bindSuccess = bindWallpaperComponentLocked(name, /* force */
                        forceRebind, /* fromUser */ true, newWallpaper, callback);
                if (bindSuccess) {
                    if (!same) {
@@ -3281,6 +3349,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
            notifyWallpaperColorsChanged(newWallpaper, which);
            notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
        }
        return bindSuccess;
    }

    // TODO(b/266818039) Remove this method