From 2ab64646fca5abb4305833b23baaa169d9ad6e5d Mon Sep 17 00:00:00 2001 From: Chris Poultney Date: Wed, 4 Jan 2023 20:36:57 +0000 Subject: [PATCH] Lock screen LWP: use WallpaperService for lock screen. Uses a second WallpaperService for the lock screen when lock and home wallpapers are different. This supports static and live wallpapers for either screen. CTS tests pass for with lock screen LWP enabled and disabled. They will be merged after visibility issues are resolved. Bug: 253507223 Test: atest WallpaperManagerTest Change-Id: I2483e3a0808f3a61598fb87e69eb582df24a3daf --- .../statusbar/phone/LockscreenWallpaper.java | 4 + .../server/wallpaper/WallpaperData.java | 61 +++ .../wallpaper/WallpaperManagerService.java | 486 ++++++++++++++++-- 3 files changed, 511 insertions(+), 40 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java index 1d7dfe1998714..0814ea593a0bb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java @@ -122,6 +122,10 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen public LoaderResult loadBitmap(int currentUserId, UserHandle selectedUser) { // May be called on any thread - only use thread safe operations. + if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) { + return LoaderResult.success(null); + } + if (!mWallpaperManager.isWallpaperSupported()) { // When wallpaper is not supported, show the system wallpaper return LoaderResult.success(null); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperData.java b/services/core/java/com/android/server/wallpaper/WallpaperData.java index 25ce28047fe17..625e7d91c66c2 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperData.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperData.java @@ -55,6 +55,12 @@ class WallpaperData { */ int mWhich; + /** + * True if the system wallpaper was also used for lock screen before this wallpaper was set. + * This is needed to update state after setting the wallpaper. + */ + boolean mSystemWasBoth; + /** * Callback once the set + crop is finished */ @@ -139,6 +145,61 @@ class WallpaperData { (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP); } + /** + * Copies the essential properties of a WallpaperData to a new instance, including the id and + * WallpaperConnection, usually in preparation for migrating a system+lock wallpaper to system- + * or lock-only. NB: the source object retains the pointer to the connection and it is the + * caller's responsibility to set this to null or otherwise be sure the connection is not shared + * between WallpaperData instances. + * + * @param source WallpaperData object to copy + */ + WallpaperData(WallpaperData source) { + this.userId = source.userId; + this.wallpaperFile = source.wallpaperFile; + this.cropFile = source.cropFile; + this.wallpaperComponent = source.wallpaperComponent; + this.mWhich = source.mWhich; + this.wallpaperId = source.wallpaperId; + this.cropHint.set(source.cropHint); + this.allowBackup = source.allowBackup; + this.primaryColors = source.primaryColors; + this.mWallpaperDimAmount = source.mWallpaperDimAmount; + this.connection = source.connection; + this.connection.mWallpaper = this; + } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(defaultString(this)); + out.append(", id: "); + out.append(wallpaperId); + out.append(", which: "); + out.append(mWhich); + out.append(", file mod: "); + out.append(wallpaperFile != null ? wallpaperFile.lastModified() : "null"); + if (connection == null) { + out.append(", no connection"); + } else { + out.append(", info: "); + out.append(connection.mInfo); + out.append(", engine(s):"); + connection.forEachDisplayConnector(connector -> { + if (connector.mEngine != null) { + out.append(" "); + out.append(defaultString(connector.mEngine)); + } else { + out.append(" null"); + } + }); + } + return out.toString(); + } + + private static String defaultString(Object o) { + return o.getClass().getSimpleName() + "@" + Integer.toHexString(o.hashCode()); + } + // Called during initialization of a given user's wallpaper bookkeeping boolean cropExists() { return cropFile.exists(); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index bf09b67f2f427..262b964ea720f 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -194,7 +194,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } private final Object mLock = new Object(); - private final boolean mEnableSeparateLockScreenEngine; + /** True to enable a second engine for lock screen wallpaper when different from system wp. */ + @VisibleForTesting + final boolean mEnableSeparateLockScreenEngine; + /** Tracks wallpaper being migrated from system+lock to lock when setting static wp. */ + WallpaperDestinationChangeHandler mPendingMigrationViaStatic; /** * Minimum time between crashes of a wallpaper service for us to consider @@ -241,11 +245,161 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return (wallpaper != null) ? wallpaper : mWallpaper; } - @Override - public void onEvent(int event, String path) { - if (path == null) { + // Handles static wallpaper changes generated by WallpaperObserver events when + // mEnableSeparateLockScreenEngine is true. + private void updateWallpapers(int event, String path) { + // System and system+lock changes happen on the system wallpaper input file; + // lock-only changes happen on the dedicated lock wallpaper input file + final File changedFile = new File(mWallpaperDir, path); + final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile)); + final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile)); + final WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged); + + final boolean moved = (event == MOVED_TO); + final boolean written = (event == CLOSE_WRITE || moved); + final boolean isMigration = moved && lockWallpaperChanged; + final boolean isRestore = moved && !isMigration; + final boolean isAppliedToLock = (wallpaper.mWhich & FLAG_LOCK) != 0; + final boolean needsUpdate = wallpaper.wallpaperComponent == null + || event != CLOSE_WRITE // includes the MOVED_TO case + || wallpaper.imageWallpaperPending; + + if (DEBUG) { + Slog.v(TAG, "Wallpaper file change: evt=" + event + + " path=" + path + + " sys=" + sysWallpaperChanged + + " lock=" + lockWallpaperChanged + + " imagePending=" + wallpaper.imageWallpaperPending + + " mWhich=0x" + Integer.toHexString(wallpaper.mWhich) + + " written=" + written + + " isMigration=" + isMigration + + " isRestore=" + isRestore + + " isAppliedToLock=" + isAppliedToLock + + " needsUpdate=" + needsUpdate); + } + + if (isMigration) { + // When separate lock screen engine is supported, migration will be handled by + // WallpaperDestinationChangeHandler. return; } + if (!(sysWallpaperChanged || lockWallpaperChanged)) { + return; + } + + int notifyColorsWhich = 0; + synchronized (mLock) { + notifyCallbacksLocked(wallpaper); + + if (!written || !needsUpdate) { + return; + } + + if (DEBUG) { + Slog.v(TAG, "Setting new static wallpaper: which=" + wallpaper.mWhich); + } + + WallpaperDestinationChangeHandler localSync = mPendingMigrationViaStatic; + mPendingMigrationViaStatic = null; + // The image source has finished writing the source image, + // so we now produce the crop rect (in the background), and + // only publish the new displayable (sub)image as a result + // of that work. + SELinux.restorecon(changedFile); + if (isRestore) { + // This is a restore, so generate the crop using any just-restored new + // crop guidelines, making sure to preserve our local dimension hints. + // We also make sure to reapply the correct SELinux label. + if (DEBUG) { + Slog.v(TAG, "Wallpaper restore; reloading metadata"); + } + loadSettingsLocked(wallpaper.userId, true); + } + if (DEBUG) { + Slog.v(TAG, "Wallpaper written; generating crop"); + } + mWallpaperCropper.generateCrop(wallpaper); + if (DEBUG) { + Slog.v(TAG, "Crop done; invoking completion callback"); + } + wallpaper.imageWallpaperPending = false; + + if (sysWallpaperChanged) { + if (DEBUG) { + Slog.v(TAG, "Home screen wallpaper changed"); + } + IRemoteCallback.Stub callback = new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle data) throws RemoteException { + if (DEBUG) { + Slog.d(TAG, "publish system wallpaper changed!"); + } + if (localSync != null) { + localSync.complete(); + } + notifyWallpaperChanged(wallpaper); + } + }; + + // If this was the system wallpaper, rebind... + bindWallpaperComponentLocked(mImageWallpaper, true, false, wallpaper, + callback); + notifyColorsWhich |= FLAG_SYSTEM; + } + + if (lockWallpaperChanged) { + // This is lock-only, so (re)bind to the static engine. + if (DEBUG) { + Slog.v(TAG, "Lock screen wallpaper changed"); + } + IRemoteCallback.Stub callback = new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle data) throws RemoteException { + if (DEBUG) { + Slog.d(TAG, "publish lock wallpaper changed!"); + } + if (localSync != null) { + localSync.complete(); + } + notifyWallpaperChanged(wallpaper); + } + }; + + bindWallpaperComponentLocked(mImageWallpaper, true /* force */, + false /* fromUser */, wallpaper, callback); + notifyColorsWhich |= FLAG_LOCK; + } else if (isAppliedToLock) { + // This is system-plus-lock: we need to wipe the lock bookkeeping since + // we're falling back to displaying the system wallpaper there. + if (DEBUG) { + Slog.v(TAG, "Lock screen wallpaper changed to same as home"); + } + final WallpaperData lockedWallpaper = mLockWallpaperMap.get( + mWallpaper.userId); + if (lockedWallpaper != null) { + detachWallpaperLocked(lockedWallpaper); + } + mLockWallpaperMap.remove(wallpaper.userId); + notifyColorsWhich |= FLAG_LOCK; + } + + saveSettingsLocked(wallpaper.userId); + // Notify the client immediately if only lockscreen wallpaper changed. + if (lockWallpaperChanged && !sysWallpaperChanged) { + notifyWallpaperChanged(wallpaper); + } + } + + // Outside of the lock since it will synchronize itself + if (notifyColorsWhich != 0) { + notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich); + } + } + + // Handles static wallpaper changes generated by WallpaperObserver events when + // mEnableSeparateLockScreenEngine is false. + // TODO(b/266818039) Remove this method + private void updateWallpapersLegacy(int event, String path) { final boolean moved = (event == MOVED_TO); final boolean written = (event == CLOSE_WRITE || moved); final File changedFile = new File(mWallpaperDir, path); @@ -268,7 +422,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } if (moved && lockWallpaperChanged) { - // TODO(b/253507223) Start lock screen WallpaperService // We just migrated sys -> lock to preserve imagery for an impending // new system-only wallpaper. Tell keyguard about it and make sure it // has the right SELinux label. @@ -323,8 +476,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub false, wallpaper, callback); notifyColorsWhich |= FLAG_SYSTEM; } - // TODO(b/253507223) Start lock screen WallpaperService if only lock - // screen wp changed if (lockWallpaperChanged || (wallpaper.mWhich & FLAG_LOCK) != 0) { if (DEBUG) { @@ -356,6 +507,19 @@ public class WallpaperManagerService extends IWallpaperManager.Stub notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich); } } + + @Override + public void onEvent(int event, String path) { + if (path == null) { + return; + } + + if (mEnableSeparateLockScreenEngine) { + updateWallpapers(event, path); + } else { + updateWallpapersLegacy(event, path); + } + } } private void notifyWallpaperChanged(WallpaperData wallpaper) { @@ -382,6 +546,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) { + if (DEBUG) { + Slog.i(TAG, "Notifying wallpaper colors changed"); + } if (wallpaper.connection != null) { wallpaper.connection.forEachDisplayConnector(connector -> { notifyWallpaperColorsChangedOnDisplay(wallpaper, which, connector.mDisplayId); @@ -807,7 +974,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub * A map for each display. * Use {@link #getDisplayConnectorOrCreate(int displayId)} to ensure the display is usable. */ - private SparseArray mDisplayConnector = new SparseArray<>(); + private final SparseArray mDisplayConnector = new SparseArray<>(); /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the * middle of an update). If exceeded, the wallpaper gets reset to the system default. */ @@ -1170,6 +1337,110 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } + /** + * Tracks wallpaper information during a wallpaper change and does bookkeeping afterwards to + * update Engine destination, wallpaper maps, and last wallpaper. + */ + class WallpaperDestinationChangeHandler { + final WallpaperData mNewWallpaper; + final WallpaperData mOriginalSystem; + + WallpaperDestinationChangeHandler(WallpaperData newWallpaper) { + this.mNewWallpaper = newWallpaper; + WallpaperData sysWp = mWallpaperMap.get(newWallpaper.userId); + mOriginalSystem = new WallpaperData(sysWp); + } + + void complete() { + // Only changes from home+lock to just home or lock need attention + // If setting the wallpaper fails, this callback will be called + // when the wallpaper is detached, in which case wallpapers may have + // already changed. Make sure we're not overwriting a more recent wallpaper. + if (mNewWallpaper.mSystemWasBoth) { + if (DEBUG) { + Slog.v(TAG, "Handling change from system+lock wallpaper"); + } + if (mNewWallpaper.mWhich == FLAG_SYSTEM) { + // New wp is system only, so old system+lock is now lock only + final boolean originalIsStatic = mImageWallpaper.equals( + mOriginalSystem.wallpaperComponent); + if (originalIsStatic) { + // Static wp: image file rename has already been tried via + // migrateStaticSystemToLockWallpaperLocked() and added to the lock wp map + // if successful. + WallpaperData lockWp = mLockWallpaperMap.get(mNewWallpaper.userId); + if (lockWp != null) { + // Successful rename, set old system+lock to the pending lock wp + if (DEBUG) { + Slog.v(TAG, "static system+lock to system success"); + } + lockWp.wallpaperComponent = + mOriginalSystem.wallpaperComponent; + lockWp.connection = mOriginalSystem.connection; + lockWp.connection.mWallpaper = lockWp; + updateEngineFlags(mOriginalSystem, FLAG_LOCK); + notifyWallpaperColorsChanged(lockWp, FLAG_LOCK); + } else { + // Failed rename, use current system wp for both + if (DEBUG) { + Slog.v(TAG, "static system+lock to system failure"); + } + WallpaperData currentSystem = mWallpaperMap.get(mNewWallpaper.userId); + currentSystem.mWhich = FLAG_SYSTEM | FLAG_LOCK; + updateEngineFlags(currentSystem, FLAG_SYSTEM | FLAG_LOCK); + mLockWallpaperMap.remove(mNewWallpaper.userId); + } + } else { + // Live wp: just update old system+lock to lock only + if (DEBUG) { + Slog.v(TAG, "live system+lock to system success"); + } + mOriginalSystem.mWhich = FLAG_LOCK; + updateEngineFlags(mOriginalSystem, FLAG_LOCK); + mLockWallpaperMap.put(mNewWallpaper.userId, mOriginalSystem); + mLastLockWallpaper = mOriginalSystem; + notifyWallpaperColorsChanged(mOriginalSystem, FLAG_LOCK); + } + } else if (mNewWallpaper.mWhich == FLAG_LOCK) { + // New wp is lock only, so old system+lock is now system only + if (DEBUG) { + Slog.v(TAG, "system+lock to lock"); + } + WallpaperData currentSystem = mWallpaperMap.get(mNewWallpaper.userId); + if (currentSystem.wallpaperId == mOriginalSystem.wallpaperId) { + currentSystem.mWhich = FLAG_SYSTEM; + updateEngineFlags(currentSystem, FLAG_SYSTEM); + } + } + } + + if (DEBUG) { + Slog.v(TAG, "--- wallpaper changed --"); + Slog.v(TAG, "new sysWp: " + mWallpaperMap.get(mCurrentUserId)); + Slog.v(TAG, "new lockWp: " + mLockWallpaperMap.get(mCurrentUserId)); + Slog.v(TAG, "new lastWp: " + mLastWallpaper); + Slog.v(TAG, "new lastLockWp: " + mLastLockWallpaper); + } + } + + private void updateEngineFlags(WallpaperData wallpaper, @SetWallpaperFlags int which) { + if (wallpaper.connection == null) { + return; + } + wallpaper.connection.forEachDisplayConnector( + connector -> { + try { + if (connector.mEngine != null) { + connector.mEngine.setWallpaperFlags(which); + } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to update wallpaper engine flags", e); + } + } + ); + } + } + class MyPackageMonitor extends PackageMonitor { @Override public void onPackageUpdateFinished(String packageName, int uid) { @@ -1345,6 +1616,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub mEnableSeparateLockScreenEngine = mContext.getResources().getBoolean( R.bool.config_independentLockscreenLiveWallpaper); + if (DEBUG) { + Slog.v(TAG, "Separate lock screen engine enabled: " + mEnableSeparateLockScreenEngine); + } LocalServices.addService(WallpaperManagerInternal.class, new LocalService()); } @@ -2467,23 +2741,33 @@ public class WallpaperManagerService extends IWallpaperManager.Stub synchronized (mLock) { if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which)); WallpaperData wallpaper; + final WallpaperData originalSystemWallpaper = mWallpaperMap.get(userId); + final boolean systemIsStatic = + originalSystemWallpaper != null && mImageWallpaper.equals( + originalSystemWallpaper.wallpaperComponent); + final boolean systemIsBoth = mLockWallpaperMap.get(userId) == null; /* If we're setting system but not lock, and lock is currently sharing the system * wallpaper, we need to migrate that image over to being lock-only before * the caller here writes new bitmap data. */ - if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) { + if (which == FLAG_SYSTEM && systemIsStatic && systemIsBoth) { Slog.i(TAG, "Migrating current wallpaper to be lock-only before" - + "updating system wallpaper"); - migrateSystemToLockWallpaperLocked(userId); + + " updating system wallpaper"); + migrateStaticSystemToLockWallpaperLocked(userId); } wallpaper = getWallpaperSafeLocked(userId, which); + if (mPendingMigrationViaStatic != null) { + Slog.w(TAG, "Starting new static wp migration before previous migration finished"); + } + mPendingMigrationViaStatic = new WallpaperDestinationChangeHandler(wallpaper); final long ident = Binder.clearCallingIdentity(); try { ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras); if (pfd != null) { wallpaper.imageWallpaperPending = true; + wallpaper.mSystemWasBoth = systemIsBoth; wallpaper.mWhich = which; wallpaper.setComplete = completion; wallpaper.fromForegroundApp = fromForegroundApp; @@ -2498,7 +2782,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - private void migrateSystemToLockWallpaperLocked(int userId) { + private void migrateStaticSystemToLockWallpaperLocked(int userId) { WallpaperData sysWP = mWallpaperMap.get(userId); if (sysWP == null) { if (DEBUG) { @@ -2520,14 +2804,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub try { Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath()); Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath()); + mLockWallpaperMap.put(userId, lockWP); + if (mEnableSeparateLockScreenEngine) { + SELinux.restorecon(lockWP.wallpaperFile); + mLastLockWallpaper = lockWP; + } } catch (ErrnoException e) { Slog.e(TAG, "Can't migrate system wallpaper: " + e.getMessage()); lockWP.wallpaperFile.delete(); lockWP.cropFile.delete(); return; } - - mLockWallpaperMap.put(userId, lockWP); } ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper, @@ -2582,11 +2869,116 @@ public class WallpaperManagerService extends IWallpaperManager.Stub @VisibleForTesting void setWallpaperComponent(ComponentName name, @SetWallpaperFlags int which, int userId) { + if (mEnableSeparateLockScreenEngine) { + setWallpaperComponentInternal(name, which, userId); + } else { + setWallpaperComponentInternalLegacy(name, which, userId); + } + } + + private void setWallpaperComponentInternal(ComponentName name, @SetWallpaperFlags int which, + int userIdIn) { + if (DEBUG) { + Slog.v(TAG, "Setting new live wallpaper: which=" + which + ", component: " + name); + } + final int userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), + userIdIn, false /* all */, true /* full */, "changing live wallpaper", + null /* pkg */); + checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); + + boolean shouldNotifyColors = false; + final WallpaperData newWallpaper; + + synchronized (mLock) { + Slog.v(TAG, "setWallpaperComponent name=" + name); + final WallpaperData originalSystemWallpaper = mWallpaperMap.get(userId); + if (originalSystemWallpaper == null) { + throw new IllegalStateException("Wallpaper not yet initialized for user " + userId); + } + final boolean systemIsStatic = mImageWallpaper.equals( + originalSystemWallpaper.wallpaperComponent); + final boolean systemIsBoth = mLockWallpaperMap.get(userId) == null; + + if (which == FLAG_SYSTEM && systemIsBoth && systemIsStatic) { + // Migrate current static system+lock wp to lock only before proceeding. + Slog.i(TAG, "Migrating current wallpaper to be lock-only before" + + "updating system wallpaper"); + migrateStaticSystemToLockWallpaperLocked(userId); + } + + newWallpaper = getWallpaperSafeLocked(userId, which); + final long ident = Binder.clearCallingIdentity(); + + try { + newWallpaper.imageWallpaperPending = false; + newWallpaper.mWhich = which; + newWallpaper.mSystemWasBoth = systemIsBoth; + final WallpaperDestinationChangeHandler + liveSync = new WallpaperDestinationChangeHandler( + newWallpaper); + boolean same = changingToSame(name, newWallpaper); + IRemoteCallback.Stub callback = new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle data) throws RemoteException { + if (DEBUG) { + Slog.d(TAG, "publish system wallpaper changed!"); + } + liveSync.complete(); + } + }; + boolean bindSuccess = bindWallpaperComponentLocked(name, /* force */ + false, /* fromUser */ true, newWallpaper, callback); + if (bindSuccess) { + if (!same) { + newWallpaper.primaryColors = null; + } else { + if (newWallpaper.connection != null) { + newWallpaper.connection.forEachDisplayConnector(displayConnector -> { + try { + if (displayConnector.mEngine != null) { + displayConnector.mEngine.dispatchWallpaperCommand( + COMMAND_REAPPLY, 0, 0, 0, null); + } + } catch (RemoteException e) { + Slog.w(TAG, "Error sending apply message to wallpaper", e); + } + }); + } + } + newWallpaper.wallpaperId = makeWallpaperIdLocked(); + notifyCallbacksLocked(newWallpaper); + shouldNotifyColors = true; + + if (which == (FLAG_SYSTEM | FLAG_LOCK)) { + if (DEBUG) { + Slog.v(TAG, "Lock screen wallpaper changed to same as home"); + } + final WallpaperData lockedWallpaper = mLockWallpaperMap.get( + newWallpaper.userId); + if (lockedWallpaper != null) { + detachWallpaperLocked(lockedWallpaper); + } + mLockWallpaperMap.remove(newWallpaper.userId); + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + if (shouldNotifyColors) { + notifyWallpaperColorsChanged(newWallpaper, which); + notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM); + } + } + + // TODO(b/266818039) Remove this method + private void setWallpaperComponentInternalLegacy(ComponentName name, + @SetWallpaperFlags int which, int userId) { userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId, false /* all */, true /* full */, "changing live wallpaper", null /* pkg */); checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); - // TODO(b/253507223) Use passed destination and properly start lock screen LWP int legacyWhich = FLAG_SYSTEM; boolean shouldNotifyColors = false; WallpaperData wallpaper; @@ -2609,7 +3001,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // therefore it's a shared system+lock image that we need to migrate. Slog.i(TAG, "Migrating current wallpaper to be lock-only before" + "updating system wallpaper"); - migrateSystemToLockWallpaperLocked(userId); + migrateStaticSystemToLockWallpaperLocked(userId); } } @@ -2689,8 +3081,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (componentName == null) { // Fall back to static image wallpaper componentName = mImageWallpaper; - //clearWallpaperComponentLocked(); - //return; if (DEBUG_LIVE) Slog.v(TAG, "No default component; using image wallpaper"); } } @@ -2713,11 +3103,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return false; } + // This will only get set for non-static wallpapers. WallpaperInfo wi = null; Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE); if (componentName != null && !componentName.equals(mImageWallpaper)) { - // Make sure the selected service is actually a wallpaper service. + // The requested component is not the static wallpaper service, so make sure it's + // actually a wallpaper service. List ris = mIPackageManager.queryIntentServices(intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), @@ -2789,13 +3181,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub intent.putExtra(Intent.EXTRA_CLIENT_LABEL, com.android.internal.R.string.wallpaper_binding_label); intent.putExtra(Intent.EXTRA_CLIENT_INTENT, clientIntent); - if (!mContext.bindServiceAsUser(intent, newConn, + boolean bindSuccess = mContext.bindServiceAsUser(intent, newConn, Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE | Context.BIND_INCLUDE_CAPABILITIES, - new UserHandle(serviceUserId))) { - String msg = "Unable to bind service: " - + componentName; + new UserHandle(serviceUserId)); + if (!bindSuccess) { + String msg = "Unable to bind service: " + componentName; if (fromUser) { throw new IllegalArgumentException(msg); } @@ -2834,15 +3226,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // Updates tracking of the currently bound wallpapers. Assumes mEnableSeparateLockScreenEngine // is true. private void updateCurrentWallpapers(WallpaperData newWallpaper) { - if (newWallpaper.userId == mCurrentUserId && !newWallpaper.equals(mFallbackWallpaper)) { - 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) { - mLastLockWallpaper = newWallpaper; - } + if (newWallpaper.userId != mCurrentUserId || newWallpaper.equals(mFallbackWallpaper)) { + return; + } + if (newWallpaper.mWhich == (FLAG_SYSTEM | FLAG_LOCK)) { + mLastWallpaper = newWallpaper; + } else if (newWallpaper.mWhich == FLAG_SYSTEM) { + mLastWallpaper = newWallpaper; + } else if (newWallpaper.mWhich == FLAG_LOCK) { + mLastLockWallpaper = newWallpaper; } } @@ -2854,10 +3246,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } boolean homeUpdated = (newWallpaper.mWhich & FLAG_SYSTEM) != 0; boolean lockUpdated = (newWallpaper.mWhich & FLAG_LOCK) != 0; - // This is the case where a home+lock wallpaper was changed to home-only, and the old - // home+lock became (static) or will become (live) lock-only. - boolean lockNeedsHomeWallpaper = mLastLockWallpaper == null && !lockUpdated; - if (mLastWallpaper != null && homeUpdated && !lockNeedsHomeWallpaper) { + boolean systemWillBecomeLock = newWallpaper.mSystemWasBoth && !lockUpdated; + if (mLastWallpaper != null && homeUpdated && !systemWillBecomeLock) { detachWallpaperLocked(mLastWallpaper); } if (mLastLockWallpaper != null && lockUpdated) { @@ -2865,8 +3255,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } + // Frees up all rendering resources used by the given wallpaper so that the WallpaperData object + // can be reused: detaches Engine, unbinds WallpaperService, etc. private void detachWallpaperLocked(WallpaperData wallpaper) { if (wallpaper.connection != null) { + if (DEBUG) { + Slog.v(TAG, "Detaching wallpaper: " + wallpaper); + } if (wallpaper.connection.mReply != null) { try { wallpaper.connection.mReply.sendResult(null); @@ -2882,7 +3277,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } catch (RemoteException e) { Slog.w(TAG, "Failed detaching wallpaper service ", e); } - mContext.unbindService(wallpaper.connection); + try { + mContext.unbindService(wallpaper.connection); + } catch (IllegalArgumentException e) { + Slog.w(TAG, "Attempted to unbind unregistered service"); + } wallpaper.connection.forEachDisplayConnector(DisplayConnector::disconnectLocked); wallpaper.connection.mService = null; wallpaper.connection.mDisplayConnector.clear(); @@ -3192,6 +3591,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } /** + * Determines and returns the current wallpaper for the given user and destination, creating + * a valid entry if it does not already exist and adding it to the appropriate wallpaper map. + * * Sometimes it is expected the wallpaper map may not have a user's data. E.g. This could * happen during user switch. The async user switch observer may not have received * the event yet. We use this safe method when we don't care about this ordering and just @@ -3215,10 +3617,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // unified lock, so we bring up the saved state lazily now and recheck. loadSettingsLocked(userId, false); wallpaper = whichSet.get(userId); - // if it's still null here, this is a lock-only operation and there is not - // yet a lock-only wallpaper set for this user, so we need to establish - // it now. if (wallpaper == null) { + // if it's still null here, this is likely a lock-only operation and there is not + // currently a lock-only wallpaper set for this user, so we need to establish + // it now. if (which == FLAG_LOCK) { wallpaper = new WallpaperData(userId, FLAG_LOCK); mLockWallpaperMap.put(userId, wallpaper); @@ -3341,6 +3743,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub WallpaperData lockWallpaper = mLockWallpaperMap.get(userId); if (lockWallpaper != null) { ensureSaneWallpaperData(lockWallpaper); + lockWallpaper.mWhich = FLAG_LOCK; + wallpaper.mWhich = FLAG_SYSTEM; + } else { + wallpaper.mWhich = FLAG_SYSTEM | FLAG_LOCK; } }