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; } }