diff options
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | api/system-current.txt | 2 | ||||
| -rw-r--r-- | api/test-current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/app/IWallpaperManager.aidl | 16 | ||||
| -rw-r--r-- | core/java/android/app/WallpaperManager.java | 91 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wallpaper/WallpaperManagerService.java | 397 |
6 files changed, 386 insertions, 122 deletions
diff --git a/api/current.txt b/api/current.txt index 96900cd4a0b7..f1f823a42043 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5721,6 +5721,7 @@ package android.app { method public android.graphics.drawable.Drawable getDrawable(); method public android.graphics.drawable.Drawable getFastDrawable(); method public static android.app.WallpaperManager getInstance(android.content.Context); + method public android.os.ParcelFileDescriptor getWallpaperFile(int); method public android.app.WallpaperInfo getWallpaperInfo(); method public boolean hasResourceWallpaper(int); method public boolean isWallpaperSettingAllowed(); diff --git a/api/system-current.txt b/api/system-current.txt index 8c4e3dc8fdb8..f326368d6c77 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5844,6 +5844,7 @@ package android.app { public class WallpaperManager { method public void clear() throws java.io.IOException; method public void clearWallpaper(); + method public void clearWallpaper(int, int); method public void clearWallpaperOffsets(android.os.IBinder); method public void forgetLoadedWallpaper(); method public android.graphics.drawable.Drawable getBuiltInDrawable(); @@ -5854,6 +5855,7 @@ package android.app { method public android.graphics.drawable.Drawable getDrawable(); method public android.graphics.drawable.Drawable getFastDrawable(); method public static android.app.WallpaperManager getInstance(android.content.Context); + method public android.os.ParcelFileDescriptor getWallpaperFile(int); method public android.app.WallpaperInfo getWallpaperInfo(); method public boolean hasResourceWallpaper(int); method public boolean isWallpaperSettingAllowed(); diff --git a/api/test-current.txt b/api/test-current.txt index 68c51a59d398..2a66162f0aba 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5723,6 +5723,7 @@ package android.app { method public android.graphics.drawable.Drawable getDrawable(); method public android.graphics.drawable.Drawable getFastDrawable(); method public static android.app.WallpaperManager getInstance(android.content.Context); + method public android.os.ParcelFileDescriptor getWallpaperFile(int); method public android.app.WallpaperInfo getWallpaperInfo(); method public boolean hasResourceWallpaper(int); method public boolean isWallpaperSettingAllowed(); diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index 04493cb0fc58..1143c6aec7a6 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -27,7 +27,7 @@ import android.content.ComponentName; interface IWallpaperManager { /** - * Set the wallpaper. + * Set the wallpaper for the current user. * * If 'extras' is non-null, on successful return it will contain: * EXTRA_SET_WALLPAPER_ID : integer ID that the new wallpaper will have @@ -56,10 +56,10 @@ interface IWallpaperManager { void setWallpaperComponent(in ComponentName name); /** - * Get the system wallpaper. + * Get the wallpaper for a given user. */ - ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, - out Bundle outParams); + ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, int which, + out Bundle outParams, int userId); /** * If the current system wallpaper is a live wallpaper component, return the @@ -71,7 +71,7 @@ interface IWallpaperManager { /** * Clear the system wallpaper. */ - void clearWallpaper(in String callingPackage); + void clearWallpaper(in String callingPackage, int which, int userId); /** * Return whether the current system wallpaper has the given name. @@ -118,4 +118,10 @@ interface IWallpaperManager { * Check whether setting of wallpapers are allowed for the calling user. */ boolean isWallpaperSettingAllowed(in String callingPackage); + + /* + * Keyguard: register a callback for being notified that lock-state relevant + * wallpaper content has changed. + */ + boolean setLockWallpaperCallback(IWallpaperManagerCallback cb); } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index eda82c0119f0..1875e6145dbd 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project +h * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,7 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; +import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.view.WindowManagerGlobal; @@ -265,11 +266,10 @@ public class WallpaperManager { private Bitmap mWallpaper; private Bitmap mDefaultWallpaper; - private static final int MSG_CLEAR_WALLPAPER = 1; - Globals(Looper looper) { IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE); mService = IWallpaperManager.Stub.asInterface(b); + forgetLoadedWallpaper(); } public void onWallpaperChanged() { @@ -278,10 +278,7 @@ public class WallpaperManager { * to null so if the user requests the wallpaper again then we'll * fetch it. */ - synchronized (this) { - mWallpaper = null; - mDefaultWallpaper = null; - } + forgetLoadedWallpaper(); } public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) { @@ -334,7 +331,8 @@ public class WallpaperManager { try { Bundle params = new Bundle(); - ParcelFileDescriptor fd = mService.getWallpaper(this, params); + ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SET_SYSTEM, + params, context.getUserId()); if (fd != null) { try { BitmapFactory.Options options = new BitmapFactory.Options(); @@ -633,7 +631,7 @@ public class WallpaperManager { * wallpaper or a null pointer if these is none. */ public Drawable peekFastDrawable() { - Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false); + Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false); if (bm != null) { return new FastBitmapDrawable(bm); } @@ -650,15 +648,49 @@ public class WallpaperManager { } /** + * Get an open, readable file descriptor to the given wallpaper image file. + * The callee is resopnsible for closing the fd when done ingesting the file. + * + * <p>If no lock-specific wallpaper has been configured for the given user, then + * this method will return {@code null} when requesting {@link #FLAG_SET_LOCK} rather than + * returning the system wallpaper's image file. + */ + public ParcelFileDescriptor getWallpaperFile(int which) { + return getWallpaperFile(which, mContext.getUserId()); + } + + /** + * Version of {@link #getWallpaperFile(int)} that can access the wallpaper data + * for a given user. The caller must hold the INTERACT_ACROSS_USERS_FULL + * permission to access another user's wallpaper data. + * @hide + */ + public ParcelFileDescriptor getWallpaperFile(int which, int userId) { + if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) { + throw new IllegalArgumentException("Must request exactly one kind of wallpaper"); + } + + if (sGlobals.mService == null) { + Log.w(TAG, "WallpaperService not running"); + return null; + } else { + try { + Bundle outParams = new Bundle(); + return sGlobals.mService.getWallpaper(null, which, outParams, userId); + } catch (RemoteException e) { + return null; + } + } + } + + /** * Remove all internal references to the last loaded wallpaper. Useful * for apps that want to reduce memory usage when they only temporarily * need to have the wallpaper. After calling, the next request for the * wallpaper will require reloading it again from disk. */ public void forgetLoadedWallpaper() { - if (isWallpaperSupported()) { - sGlobals.forgetLoadedWallpaper(); - } + sGlobals.forgetLoadedWallpaper(); } /** @@ -1209,12 +1241,23 @@ public class WallpaperManager { */ @SystemApi public void clearWallpaper() { + clearWallpaper(FLAG_SET_SYSTEM, mContext.getUserId()); + } + + /** + * Clear the wallpaper for a specific user. The caller must hold the + * INTERACT_ACROSS_USERS_FULL permission to clear another user's + * wallpaper. + * @hide + */ + @SystemApi + public void clearWallpaper(int which, int userId) { if (sGlobals.mService == null) { Log.w(TAG, "WallpaperService not running"); return; } try { - sGlobals.mService.clearWallpaper(mContext.getOpPackageName()); + sGlobals.mService.clearWallpaper(mContext.getOpPackageName(), which, userId); } catch (RemoteException e) { // Ignore } @@ -1363,7 +1406,7 @@ public class WallpaperManager { } /** - * Remove any currently set wallpaper, reverting to the system's built-in + * 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. * @@ -1424,6 +1467,26 @@ public class WallpaperManager { return null; } + /** + * Register a callback for lock wallpaper observation. Only the OS may use this. + * + * @return true on success; false on error. + * @hide + */ + public boolean setLockWallpaperCallback(IWallpaperManagerCallback callback) { + if (sGlobals.mService == null) { + Log.w(TAG, "WallpaperService not running"); + return false; + } + + try { + return sGlobals.mService.setLockWallpaperCallback(callback); + } catch (RemoteException e) { + Log.e(TAG, "Unable to contact wallpaper service"); + } + return false; + } + // Private completion callback for setWallpaper() synchronization private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub { final CountDownLatch mLatch; diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 09c53aeff81e..7387f020968d 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -16,6 +16,8 @@ package com.android.server.wallpaper; +import static android.app.WallpaperManager.FLAG_SET_SYSTEM; +import static android.app.WallpaperManager.FLAG_SET_LOCK; import static android.os.ParcelFileDescriptor.*; import android.app.ActivityManagerNative; @@ -104,7 +106,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { static final String TAG = "WallpaperManagerService"; static final boolean DEBUG = true; - final Object mLock = new Object[0]; + final Object mLock = new Object(); /** * Minimum time between crashes of a wallpaper service for us to consider @@ -114,8 +116,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128; static final String WALLPAPER = "wallpaper_orig"; static final String WALLPAPER_CROP = "wallpaper"; + static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig"; + static final String WALLPAPER_LOCK_CROP = "wallpaper_lock"; static final String WALLPAPER_INFO = "wallpaper_info.xml"; + // All the various per-user state files we need to be aware of + static final String[] sPerUserFiles = new String[] { + WALLPAPER, WALLPAPER_CROP, + WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP, + WALLPAPER_INFO + }; + /** * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks * that the wallpaper has changed. The CREATE is triggered when there is no @@ -124,22 +135,38 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { */ private class WallpaperObserver extends FileObserver { + final int mUserId; final WallpaperData mWallpaper; final File mWallpaperDir; final File mWallpaperFile; - final File mWallpaperCropFile; + final File mWallpaperLockFile; final File mWallpaperInfoFile; public WallpaperObserver(WallpaperData wallpaper) { super(getWallpaperDir(wallpaper.userId).getAbsolutePath(), CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF); + mUserId = wallpaper.userId; mWallpaperDir = getWallpaperDir(wallpaper.userId); mWallpaper = wallpaper; mWallpaperFile = new File(mWallpaperDir, WALLPAPER); - mWallpaperCropFile = new File(mWallpaperDir, WALLPAPER_CROP); + mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG); mWallpaperInfoFile = new File(mWallpaperDir, WALLPAPER_INFO); } + private WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) { + WallpaperData wallpaper = null; + synchronized (mLock) { + if (lockChanged) { + wallpaper = mLockWallpaperMap.get(mUserId); + } + if (wallpaper == null) { + // no lock-specific wallpaper exists, or sys case, handled together + wallpaper = mWallpaperMap.get(mUserId); + } + } + return (wallpaper != null) ? wallpaper : mWallpaper; + } + @Override public void onEvent(int event, String path) { if (path == null) { @@ -148,38 +175,77 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { final boolean written = (event == CLOSE_WRITE || event == MOVED_TO); final File changedFile = new File(mWallpaperDir, 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 boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile)); + final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile)); + WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged); + + if (DEBUG) { + Slog.v(TAG, "Wallpaper file change: evt=" + event + + " path=" + path + + " sys=" + sysWallpaperChanged + + " lock=" + lockWallpaperChanged + + " imagePending=" + wallpaper.imageWallpaperPending + + " whichPending=0x" + Integer.toHexString(wallpaper.whichPending) + + " written=" + written); + } synchronized (mLock) { - if (mWallpaperFile.equals(changedFile) - || mWallpaperInfoFile.equals(changedFile)) { + if (sysWallpaperChanged || mWallpaperInfoFile.equals(changedFile)) { // changing the wallpaper means we'll need to back up the new one long origId = Binder.clearCallingIdentity(); BackupManager bm = new BackupManager(mContext); bm.dataChanged(); Binder.restoreCallingIdentity(origId); } - if (mWallpaperFile.equals(changedFile)) { - notifyCallbacksLocked(mWallpaper); - if (mWallpaper.wallpaperComponent == null + if (sysWallpaperChanged || lockWallpaperChanged) { + notifyCallbacksLocked(wallpaper); + if (wallpaper.wallpaperComponent == null || event != CLOSE_WRITE // includes the MOVED_TO case - || mWallpaper.imageWallpaperPending) { + || wallpaper.imageWallpaperPending) { if (written) { // 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. - generateCrop(mWallpaper); - mWallpaper.imageWallpaperPending = false; - if (mWallpaper.setComplete != null) { + if (DEBUG) { + Slog.v(TAG, "Wallpaper written; generating crop"); + } + generateCrop(wallpaper); + if (DEBUG) { + Slog.v(TAG, "Crop done; invoking completion callback"); + } + wallpaper.imageWallpaperPending = false; + if (wallpaper.setComplete != null) { try { - mWallpaper.setComplete.onWallpaperChanged(); + wallpaper.setComplete.onWallpaperChanged(); } catch (RemoteException e) { // if this fails we don't really care; the setting app may just // have crashed and that sort of thing is a fact of life. } } - bindWallpaperComponentLocked(mImageWallpaper, true, - false, mWallpaper, null); - saveSettingsLocked(mWallpaper); + if (sysWallpaperChanged) { + // If this was the system wallpaper, rebind... + bindWallpaperComponentLocked(mImageWallpaper, true, + false, wallpaper, null); + } + if (lockWallpaperChanged + || (wallpaper.whichPending & FLAG_SET_LOCK) != 0) { + // either a lock-only wallpaper commit or a system+lock event, + // so tell keyguard about it + if (DEBUG) { + Slog.i(TAG, "Lock-relevant wallpaper changed; telling listener"); + } + final IWallpaperManagerCallback cb = mKeyguardListener; + if (cb != null) { + try { + cb.onWallpaperChanged(); + } catch (RemoteException e) { + // Oh well it went away; no big deal + } + } + } + saveSettingsLocked(wallpaper); } } } @@ -194,12 +260,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { private void generateCrop(WallpaperData wallpaper) { boolean success = false; boolean needCrop = false; + boolean needScale = false; + + if (DEBUG) { + Slog.v(TAG, "Generating crop for new wallpaper(s): 0x" + + Integer.toHexString(wallpaper.whichPending) + + " to " + wallpaper.cropFile.getName()); + } // Analyse the source; needed in multiple cases BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options); + // We'll need to scale if the crop is sufficiently bigger than the display + // Legacy case uses an empty crop rect here, so we just preserve the // source image verbatim if (!wallpaper.cropHint.isEmpty()) { @@ -211,7 +286,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { && options.outWidth >= wallpaper.cropHint.width()); } - if (!needCrop) { + if (!needCrop && !needScale) { // Simple case: the nominal crop is at least as big as the source image, // so we take the whole thing and just copy the image file directly. if (DEBUG) { @@ -223,7 +298,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { // TODO: fall back to default wallpaper in this case } } else { - // Fancy case: the crop is a subrect of the source + // Fancy case: crop and/or scale FileOutputStream f = null; BufferedOutputStream bos = null; try { @@ -270,6 +345,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { final MyPackageMonitor mMonitor; final AppOpsManager mAppOpsManager; WallpaperData mLastWallpaper; + IWallpaperManagerCallback mKeyguardListener; /** * ID of the current wallpaper, changed every time anything sets a wallpaper. @@ -283,7 +359,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { */ final ComponentName mImageWallpaper; - SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>(); + final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>(); + final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>(); int mCurrentUserId; @@ -291,15 +368,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { int userId; - final File wallpaperFile; - final File cropFile; + final File wallpaperFile; // source image + final File cropFile; // eventual destination /** - * Client is currently writing a new image wallpaper. + * True while the client is writing a new wallpaper */ boolean imageWallpaperPending; /** + * Which new wallpapers are being written; mirrors the 'which' + * selector bit field to setWallpaper(). + */ + int whichPending; + + /** * Callback once the set + crop is finished */ IWallpaperManagerCallback setComplete; @@ -345,13 +428,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { final Rect padding = new Rect(0, 0, 0, 0); - WallpaperData(int userId) { + WallpaperData(int userId, String inputFileName, String cropFileName) { this.userId = userId; - wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER); - cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP); + final File wallpaperDir = getWallpaperDir(userId); + wallpaperFile = new File(wallpaperDir, inputFileName); + cropFile = new File(wallpaperDir, cropFileName); } - // Only called in single-threaded boot sequence mode + // Called during initialization of a given user's wallpaper bookkeeping boolean ensureCropExists() { // if the crop file is not present, copy over the source image to use verbatim if (!cropFile.exists()) { @@ -419,7 +503,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME > SystemClock.uptimeMillis()) { Slog.w(TAG, "Reverting to built-in wallpaper!"); - clearWallpaperLocked(true, mWallpaper.userId, null); + clearWallpaperLocked(true, FLAG_SET_SYSTEM, mWallpaper.userId, null); } else { mWallpaper.lastDiedTime = SystemClock.uptimeMillis(); } @@ -498,7 +582,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { if (!bindWallpaperComponentLocked(comp, false, false, wallpaper, null)) { Slog.w(TAG, "Wallpaper no longer available; reverting to default"); - clearWallpaperLocked(false, wallpaper.userId, null); + clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null); } } } @@ -578,7 +662,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { if (doit) { Slog.w(TAG, "Wallpaper uninstalled, removing: " + wallpaper.wallpaperComponent); - clearWallpaperLocked(false, wallpaper.userId, null); + clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null); } } } @@ -598,7 +682,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } catch (NameNotFoundException e) { Slog.w(TAG, "Wallpaper component gone, removing: " + wallpaper.wallpaperComponent); - clearWallpaperLocked(false, wallpaper.userId, null); + clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null); } } if (wallpaper.nextWallpaperComponent != null @@ -646,7 +730,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { if (DEBUG) Slog.v(TAG, "systemReady"); WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM); if (!wallpaper.ensureCropExists()) { - clearWallpaperLocked(false, UserHandle.USER_SYSTEM, null); + clearWallpaperLocked(false, FLAG_SET_SYSTEM, UserHandle.USER_SYSTEM, null); } switchWallpaper(wallpaper, null); wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper); @@ -706,37 +790,38 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } - void onStoppingUser(int userId) { - if (userId < 1) return; - synchronized (mLock) { - WallpaperData wallpaper = mWallpaperMap.get(userId); - if (wallpaper != null) { - if (wallpaper.wallpaperObserver != null) { - wallpaper.wallpaperObserver.stopWatching(); - wallpaper.wallpaperObserver = null; - } - mWallpaperMap.remove(userId); + void stopObserver(WallpaperData wallpaper) { + if (wallpaper != null) { + if (wallpaper.wallpaperObserver != null) { + wallpaper.wallpaperObserver.stopWatching(); + wallpaper.wallpaperObserver = null; } } } + void stopObserversLocked(int userId) { + stopObserver(mWallpaperMap.get(userId)); + stopObserver(mLockWallpaperMap.get(userId)); + mWallpaperMap.remove(userId); + mLockWallpaperMap.remove(userId); + } + void onRemoveUser(int userId) { if (userId < 1) return; + + final File wallpaperDir = getWallpaperDir(userId); synchronized (mLock) { - onStoppingUser(userId); - File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER); - wallpaperFile.delete(); - File cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP); - cropFile.delete(); - File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO); - wallpaperInfoFile.delete(); + stopObserversLocked(userId); + for (String filename : sPerUserFiles) { + new File(wallpaperDir, filename).delete(); + } } } void switchUser(int userId, IRemoteCallback reply) { synchronized (mLock) { mCurrentUserId = userId; - WallpaperData wallpaper = getWallpaperSafeLocked(userId); + WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM); // Not started watching yet, in case wallpaper data was loaded for other reasons. if (wallpaper.wallpaperObserver == null) { wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper); @@ -759,32 +844,71 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { e = e1; } Slog.w(TAG, "Failure starting previous wallpaper", e); - clearWallpaperLocked(false, wallpaper.userId, reply); + clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, reply); } } - public void clearWallpaper(String callingPackage) { + @Override + public void clearWallpaper(String callingPackage, int which, int userId) { if (DEBUG) Slog.v(TAG, "clearWallpaper"); checkPermission(android.Manifest.permission.SET_WALLPAPER); if (!isWallpaperSupported(callingPackage) || !isWallpaperSettingAllowed(callingPackage)) { return; } + if (userId != UserHandle.getCallingUserId()) { + // cross-user call + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + "WallpaperManagerService"); + } + synchronized (mLock) { - clearWallpaperLocked(false, UserHandle.getCallingUserId(), null); + clearWallpaperLocked(false, which, userId, null); } } - void clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply) { - WallpaperData wallpaper = mWallpaperMap.get(userId); + void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) { + if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) { + throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read"); + } + + WallpaperData wallpaper = null; + if (which == FLAG_SET_LOCK) { + wallpaper = mLockWallpaperMap.get(userId); + if (wallpaper == null) { + // It's already gone; we're done. + return; + } + } else { + wallpaper = mWallpaperMap.get(userId); + if (wallpaper == null) { + // Might need to bring it in the first time to establish our rewrite + loadSettingsLocked(userId); + wallpaper = mWallpaperMap.get(userId); + } + } if (wallpaper == null) { return; } - if (wallpaper.wallpaperFile.exists()) { - wallpaper.wallpaperFile.delete(); - wallpaper.cropFile.delete(); - } + final long ident = Binder.clearCallingIdentity(); try { + if (wallpaper.wallpaperFile.exists()) { + wallpaper.wallpaperFile.delete(); + wallpaper.cropFile.delete(); + if (which == FLAG_SET_LOCK) { + final IWallpaperManagerCallback cb = mKeyguardListener; + if (cb != null) { + try { + cb.onWallpaperChanged(); + } catch (RemoteException e) { + // Oh well it went away; no big deal + } + } + return; + } + } + RuntimeException e = null; try { wallpaper.imageWallpaperPending = false; @@ -859,7 +983,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } synchronized (mLock) { int userId = UserHandle.getCallingUserId(); - WallpaperData wallpaper = getWallpaperSafeLocked(userId); + WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM); if (width <= 0 || height <= 0) { throw new IllegalArgumentException("width and height must be > 0"); } @@ -921,7 +1045,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } synchronized (mLock) { int userId = UserHandle.getCallingUserId(); - WallpaperData wallpaper = getWallpaperSafeLocked(userId); + WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM); if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) { throw new IllegalArgumentException("padding must be positive: " + padding); } @@ -948,19 +1072,31 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } - public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, - Bundle outParams) { + public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, final int which, + Bundle outParams, int wallpaperUserId) { + if (wallpaperUserId != UserHandle.getCallingUserId()) { + // cross-user call + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + "WallpaperManagerService"); + } + + if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) { + throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read"); + } + synchronized (mLock) { - // This returns the current user's wallpaper, if called by a system service. Else it - // returns the wallpaper for the calling user. - int callingUid = Binder.getCallingUid(); - int wallpaperUserId = 0; - if (callingUid == android.os.Process.SYSTEM_UID) { - wallpaperUserId = mCurrentUserId; + WallpaperData wallpaper = null; + if (which == FLAG_SET_LOCK) { + wallpaper = mLockWallpaperMap.get(wallpaperUserId); + if (wallpaper == null) { + // If you ask for the lock wallpaper specifically and there isn't one, + // we say so rather than returning the system wallpaper as fallback. + return null; + } } else { - wallpaperUserId = UserHandle.getUserId(callingUid); + wallpaper = mWallpaperMap.get(wallpaperUserId); } - WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId); if (wallpaper == null) { return null; } @@ -994,11 +1130,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } @Override + public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) { + checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW); + synchronized (mLock) { + mKeyguardListener = cb; + } + return true; + } + + @Override public ParcelFileDescriptor setWallpaper(String name, String callingPackage, Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) { checkPermission(android.Manifest.permission.SET_WALLPAPER); - if (which == 0) { + if ((which & (FLAG_SET_LOCK|FLAG_SET_SYSTEM)) == 0) { + Slog.e(TAG, "Must specify a valid wallpaper category to set"); return null; } @@ -1017,15 +1163,19 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } + final int userId = UserHandle.getCallingUserId(); + synchronized (mLock) { - if (DEBUG) Slog.v(TAG, "setWallpaper"); - int userId = UserHandle.getCallingUserId(); - WallpaperData wallpaper = getWallpaperSafeLocked(userId); + if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which)); + WallpaperData wallpaper; + + wallpaper = getWallpaperSafeLocked(userId, which); final long ident = Binder.clearCallingIdentity(); try { ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras); if (pfd != null) { wallpaper.imageWallpaperPending = true; + wallpaper.whichPending = which; wallpaper.setComplete = completion; wallpaper.cropHint.set(cropHint); } @@ -1048,10 +1198,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1); } - File file = new File(dir, WALLPAPER); - ParcelFileDescriptor fd = ParcelFileDescriptor.open(file, + ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile, MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE); - if (!SELinux.restorecon(file)) { + if (!SELinux.restorecon(wallpaper.wallpaperFile)) { return null; } wallpaper.name = name; @@ -1061,7 +1210,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } if (DEBUG) { Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId - + " name=" + name); + + " name=" + name + " file=" + wallpaper.wallpaperFile.getName()); } return fd; } catch (FileNotFoundException e) { @@ -1417,11 +1566,36 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { * want to update the data. The data is going to be applied when the user switch observer * is eventually executed. */ - private WallpaperData getWallpaperSafeLocked(int userId) { - WallpaperData wallpaper = mWallpaperMap.get(userId); + private WallpaperData getWallpaperSafeLocked(int userId, int which) { + // We're setting either just system (work with the system wallpaper), + // both (also work with the system wallpaper), or just the lock + // wallpaper (update against the existing lock wallpaper if any). + // Combined or just-system operations use the 'system' WallpaperData + // for this use; lock-only operations use the dedicated one. + final SparseArray<WallpaperData> whichSet = + (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap; + WallpaperData wallpaper = whichSet.get(userId); if (wallpaper == null) { + // common case, this is the first lookup post-boot of the system or + // unified lock, so we bring up the saved state lazily now and recheck. loadSettingsLocked(userId); - wallpaper = mWallpaperMap.get(userId); + 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 (which == FLAG_SET_LOCK) { + wallpaper = new WallpaperData(userId, + WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); + mLockWallpaperMap.put(userId, wallpaper); + } else { + // sanity fallback: we're in bad shape, but establishing a known + // valid system+lock WallpaperData will keep us from dying. + Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!"); + wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP); + mWallpaperMap.put(userId, wallpaper); + } + } } return wallpaper; } @@ -1438,8 +1612,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } WallpaperData wallpaper = mWallpaperMap.get(userId); if (wallpaper == null) { - wallpaper = new WallpaperData(userId); + wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP); mWallpaperMap.put(userId, wallpaper); + wallpaper.ensureCropExists(); } boolean success = false; try { @@ -1453,28 +1628,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { if (type == XmlPullParser.START_TAG) { String tag = parser.getName(); if ("wp".equals(tag)) { - final String idString = parser.getAttributeValue(null, "id"); - if (idString != null) { - final int id = wallpaper.wallpaperId = Integer.parseInt(idString); - if (id > mWallpaperId) { - mWallpaperId = id; - } - } else { - wallpaper.wallpaperId = makeWallpaperIdLocked(); - } + // Common to system + lock wallpapers + parseWallpaperAttributes(parser, wallpaper); - wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width")); - wallpaper.height = Integer.parseInt(parser - .getAttributeValue(null, "height")); - wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0); - wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0); - wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0); - wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0); - wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0); - wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0); - wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0); - wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0); - wallpaper.name = parser.getAttributeValue(null, "name"); + // A system wallpaper might also be a live wallpaper String comp = parser.getAttributeValue(null, "component"); wallpaper.nextWallpaperComponent = comp != null ? ComponentName.unflattenFromString(comp) @@ -1493,6 +1650,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { Slog.v(TAG, "mNextWallpaperComponent:" + wallpaper.nextWallpaperComponent); } + } else if ("kwp".equals(tag)) { + // keyguard-specific wallpaper for this user + WallpaperData lockWallpaper = mLockWallpaperMap.get(userId); + if (lockWallpaper == null) { + lockWallpaper = new WallpaperData(userId, + WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); + mLockWallpaperMap.put(userId, lockWallpaper); + } + parseWallpaperAttributes(parser, lockWallpaper); } } } while (type != XmlPullParser.END_DOCUMENT); @@ -1543,6 +1709,31 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } + private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper) { + final String idString = parser.getAttributeValue(null, "id"); + if (idString != null) { + final int id = wallpaper.wallpaperId = Integer.parseInt(idString); + if (id > mWallpaperId) { + mWallpaperId = id; + } + } else { + wallpaper.wallpaperId = makeWallpaperIdLocked(); + } + + wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width")); + wallpaper.height = Integer.parseInt(parser + .getAttributeValue(null, "height")); + wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0); + wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0); + wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0); + wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0); + wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0); + wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0); + wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0); + wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0); + wallpaper.name = parser.getAttributeValue(null, "name"); + } + private int getMaximumSizeDimension() { WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); Display d = wm.getDefaultDisplay(); |