Merge "Expanded wallpaper APIs for keyguard and change detection"
diff --git a/api/current.txt b/api/current.txt
index e0b92f4..729f4da 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5686,10 +5686,13 @@
     method public android.graphics.drawable.Drawable peekFastDrawable();
     method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
     method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
-    method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public void setResource(int) throws java.io.IOException;
+    method public int setResource(int, int) throws java.io.IOException;
     method public void setStream(java.io.InputStream) throws java.io.IOException;
-    method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public void setWallpaperOffsetSteps(float, float);
     method public void setWallpaperOffsets(android.os.IBinder, float, float);
     method public void suggestDesiredDimensions(int, int);
@@ -5700,6 +5703,8 @@
     field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
     field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
     field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
+    field public static final int FLAG_SET_LOCK = 2; // 0x2
+    field public static final int FLAG_SET_SYSTEM = 1; // 0x1
     field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index a21dc27..da83f6a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5818,12 +5818,15 @@
     method public android.graphics.drawable.Drawable peekFastDrawable();
     method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
     method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
-    method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public void setDisplayOffset(android.os.IBinder, int, int);
     method public void setDisplayPadding(android.graphics.Rect);
     method public void setResource(int) throws java.io.IOException;
+    method public int setResource(int, int) throws java.io.IOException;
     method public void setStream(java.io.InputStream) throws java.io.IOException;
-    method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public boolean setWallpaperComponent(android.content.ComponentName);
     method public void setWallpaperOffsetSteps(float, float);
     method public void setWallpaperOffsets(android.os.IBinder, float, float);
@@ -5835,6 +5838,8 @@
     field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
     field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
     field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
+    field public static final int FLAG_SET_LOCK = 2; // 0x2
+    field public static final int FLAG_SET_SYSTEM = 1; // 0x1
     field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index f003875..4193cad 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5688,10 +5688,13 @@
     method public android.graphics.drawable.Drawable peekFastDrawable();
     method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
     method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
-    method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public void setResource(int) throws java.io.IOException;
+    method public int setResource(int, int) throws java.io.IOException;
     method public void setStream(java.io.InputStream) throws java.io.IOException;
-    method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public void setWallpaperOffsetSteps(float, float);
     method public void setWallpaperOffsets(android.os.IBinder, float, float);
     method public void suggestDesiredDimensions(int, int);
@@ -5702,6 +5705,8 @@
     field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
     field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
     field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
+    field public static final int FLAG_SET_LOCK = 2; // 0x2
+    field public static final int FLAG_SET_SYSTEM = 1; // 0x1
     field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index ccba250..7a0e7f6 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -28,37 +28,47 @@
 
     /**
      * Set the wallpaper.
+     *
+     * If 'extras' is non-null, on successful return it will contain:
+     *   EXTRA_SET_WALLPAPER_ID : integer ID that the new wallpaper will have
+     *
+     * 'which' is some combination of:
+     *   FLAG_SET_SYSTEM
+     *   FLAG_SET_LOCK
      */
-    ParcelFileDescriptor setWallpaper(String name, in String callingPackage);
+    ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
+            out Bundle extras, int which);
     
     /**
-     * Set the live wallpaper.
+     * Set the live wallpaper. This only affects the system wallpaper.
      */
     void setWallpaperComponentChecked(in ComponentName name, in String callingPackage);
 
     /**
-     * Set the live wallpaper.
+     * Set the live wallpaper. This only affects the system wallpaper.
      */
     void setWallpaperComponent(in ComponentName name);
 
     /**
-     * Get the wallpaper.
+     * Get the system wallpaper.
      */
     ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
             out Bundle outParams);
     
     /**
-     * Get information about a live wallpaper.
+     * If the current system wallpaper is a live wallpaper component, return the
+     * information about that wallpaper.  Otherwise, if it is a static image,
+     * simply return null.
      */
     WallpaperInfo getWallpaperInfo();
     
     /**
-     * Clear the wallpaper.
+     * Clear the system wallpaper.
      */
     void clearWallpaper(in String callingPackage);
 
     /**
-     * Return whether there is a wallpaper set with the given name.
+     * Return whether the current system wallpaper has the given name.
      */
     boolean hasNamedWallpaper(String name);
 
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 5b5bba4..f103576 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.IntDef;
 import android.annotation.RawRes;
 import android.annotation.SystemApi;
 import android.content.ComponentName;
@@ -60,6 +61,8 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 
 /**
@@ -144,7 +147,33 @@
      * and y arguments are the location of the drop.
      */
     public static final String COMMAND_DROP = "android.home.drop";
-    
+
+    /**
+     * Extra passed back from setWallpaper() giving the new wallpaper's assigned ID.
+     * @hide
+     */
+    public static final String EXTRA_NEW_WALLPAPER_ID = "android.service.wallpaper.extra.ID";
+
+    // flags for which kind of wallpaper to set
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            FLAG_SET_SYSTEM,
+            FLAG_SET_LOCK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SetWallpaperFlags {}
+
+    /**
+     * Flag: use the supplied imagery as the general system wallpaper.
+     */
+    public static final int FLAG_SET_SYSTEM = 1 << 0;
+
+    /**
+     * Flag: use the supplied imagery as the lock-screen wallpaper.
+     */
+    public static final int FLAG_SET_LOCK = 1 << 1;
+
     private final Context mContext;
     
     /**
@@ -717,20 +746,41 @@
      * wallpaper.
      */
     public void setResource(@RawRes int resid) throws IOException {
+        setResource(resid, FLAG_SET_SYSTEM);
+    }
+
+    /**
+     * Version of {@link #setResource(int)} that takes an optional Bundle for returning
+     * metadata about the operation to the caller.
+     *
+     * @param resid
+     * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
+     *
+     * @see #FLAG_SET_LOCK
+     * @see #FLAG_SET_SYSTEM
+     *
+     * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
+     *
+     * @throws IOException
+     */
+    public int setResource(@RawRes int resid, @SetWallpaperFlags int which)
+            throws IOException {
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
-            return;
+            return 0;
         }
+        final Bundle result = new Bundle();
         try {
             Resources resources = mContext.getResources();
             /* Set the wallpaper to the default values */
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
-                    "res:" + resources.getResourceName(resid), mContext.getOpPackageName());
+                    "res:" + resources.getResourceName(resid),
+                    mContext.getOpPackageName(), result, which);
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
                     fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
-                    setWallpaper(resources.openRawResource(resid), fos);
+                    copyStreamToWallpaperFile(resources.openRawResource(resid), fos);
                 } finally {
                     IoUtils.closeQuietly(fos);
                 }
@@ -738,6 +788,7 @@
         } catch (RemoteException e) {
             // Ignore
         }
+        return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
     }
 
     /**
@@ -753,7 +804,7 @@
      * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#SET_WALLPAPER}.
      *
-     * @param bitmap The bitmap to save.
+     * @param bitmap The bitmap to be used as the new system wallpaper.
      *
      * @throws IOException If an error occurs when attempting to set the wallpaper
      *     to the provided image.
@@ -775,42 +826,72 @@
      * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#SET_WALLPAPER}.
      *
-     * @param fullImage A bitmap that will supply the wallpaper imagery. 
+     * @param fullImage A bitmap that will supply the wallpaper imagery.
      * @param visibleCropHint The rectangular subregion of {@code fullImage} that should be
      *     displayed as wallpaper.  Passing {@code null} for this parameter means that
      *     the full image should be displayed if possible given the image's and device's
-     *     aspect ratios, etc. 
+     *     aspect ratios, etc.
      * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
      *     image for restore to a future device; {@code false} otherwise.
      *
+     * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
+     *
      * @throws IOException If an error occurs when attempting to set the wallpaper
      *     to the provided image.
      * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
      *     empty or invalid.
      */
-    public void setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
+    public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
+            throws IOException {
+        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+    }
+
+    /**
+    /**
+     * Version of {@link #setBitmap(Bitmap, Rect, boolean)} that allows the caller
+     * to specify which of the supported wallpaper categories to set.
+     *
+     * @param fullImage A bitmap that will supply the wallpaper imagery.
+     * @param visibleCropHint The rectangular subregion of {@code fullImage} that should be
+     *     displayed as wallpaper.  Passing {@code null} for this parameter means that
+     *     the full image should be displayed if possible given the image's and device's
+     *     aspect ratios, etc.
+     * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
+     *     image for restore to a future device; {@code false} otherwise.
+     * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
+     *
+     * @see #FLAG_SET_LOCK_WALLPAPER
+     * @see #FLAG_SET_SYSTEM_WALLPAPER
+     *
+     * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
+     *
+     * @throws IOException
+     */
+    public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
+            boolean allowBackup, @SetWallpaperFlags int which)
             throws IOException {
         validateRect(visibleCropHint);
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
-            return;
+            return 0;
         }
+        final Bundle result = new Bundle();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName());
-            if (fd == null) {
-                return;
-            }
-            FileOutputStream fos = null;
-            try {
-                fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
-                fullImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
-            } finally {
-                IoUtils.closeQuietly(fos);
+                    mContext.getOpPackageName(), result, which);
+            if (fd != null) {
+                FileOutputStream fos = null;
+                try {
+                    fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+                    fullImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
+                } finally {
+                    IoUtils.closeQuietly(fos);
+                }
             }
         } catch (RemoteException e) {
             // Ignore
         }
+        return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
     }
 
     private final void validateRect(Rect rect) {
@@ -843,7 +924,7 @@
         setStream(bitmapData, null, true);
     }
 
-    private void setWallpaper(InputStream data, FileOutputStream fos)
+    private void copyStreamToWallpaperFile(InputStream data, FileOutputStream fos)
             throws IOException {
         byte[] buffer = new byte[32768];
         int amt;
@@ -877,29 +958,55 @@
      * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
      *     empty or invalid.
      */
-    public void setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
+    public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
             throws IOException {
+        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+    }
+
+    /**
+     * Version of {@link #setStream(InputStream, Rect, boolean)} that allows the caller
+     * to specify which of the supported wallpaper categories to set.
+     *
+     * @param bitmapData A stream containing the raw data to install as a wallpaper.
+     * @param visibleCropHint The rectangular subregion of the streamed image that should be
+     *     displayed as wallpaper.  Passing {@code null} for this parameter means that
+     *     the full image should be displayed if possible given the image's and device's
+     *     aspect ratios, etc.
+     * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
+     *     image for restore to a future device; {@code false} otherwise.
+     * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
+     *
+     * @see #FLAG_SET_LOCK_WALLPAPER
+     * @see #FLAG_SET_SYSTEM_WALLPAPER
+     *
+     * @throws IOException
+     */
+    public int setStream(InputStream bitmapData, Rect visibleCropHint,
+            boolean allowBackup, @SetWallpaperFlags int which)
+                    throws IOException {
         validateRect(visibleCropHint);
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
-            return;
+            return 0;
         }
+        final Bundle result = new Bundle();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName());
-            if (fd == null) {
-                return;
-            }
-            FileOutputStream fos = null;
-            try {
-                fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
-                setWallpaper(bitmapData, fos);
-            } finally {
-                IoUtils.closeQuietly(fos);
+                    mContext.getOpPackageName(), result, which);
+            if (fd != null) {
+                FileOutputStream fos = null;
+                try {
+                    fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+                    copyStreamToWallpaperFile(bitmapData, fos);
+                } finally {
+                    IoUtils.closeQuietly(fos);
+                }
             }
         } catch (RemoteException e) {
             // Ignore
         }
+
+        return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 87d0700..39983dd 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -92,6 +92,8 @@
 import com.android.internal.R;
 import com.android.server.EventLogTags;
 
+import libcore.io.IoUtils;
+
 public class WallpaperManagerService extends IWallpaperManager.Stub {
     static final String TAG = "WallpaperManagerService";
     static final boolean DEBUG = false;
@@ -170,6 +172,12 @@
     WallpaperData mLastWallpaper;
 
     /**
+     * ID of the current wallpaper, changed every time anything sets a wallpaper.
+     * This is used for external detection of wallpaper update activity.
+     */
+    int mWallpaperId;
+
+    /**
      * Name of the component used to display bitmap wallpapers from either the gallery or
      * built-in wallpapers.
      */
@@ -205,6 +213,11 @@
          */
         ComponentName nextWallpaperComponent;
 
+        /**
+         * The ID of this wallpaper
+         */
+        int wallpaperId;
+
         WallpaperConnection connection;
         long lastDiedTime;
         boolean wallpaperUpdating;
@@ -227,6 +240,13 @@
         }
     }
 
+    int makeWallpaperIdLocked() {
+        do {
+            ++mWallpaperId;
+        } while (mWallpaperId == 0);
+        return mWallpaperId;
+    }
+
     class WallpaperConnection extends IWallpaperConnection.Stub
             implements ServiceConnection {
         final WallpaperInfo mInfo;
@@ -333,7 +353,7 @@
         public ParcelFileDescriptor setWallpaper(String name) {
             synchronized (mLock) {
                 if (mWallpaper.connection == this) {
-                    return updateWallpaperBitmapLocked(name, mWallpaper);
+                    return updateWallpaperBitmapLocked(name, mWallpaper, null);
                 }
                 return null;
             }
@@ -848,18 +868,26 @@
         }
     }
 
-    public ParcelFileDescriptor setWallpaper(String name, String callingPackage) {
+    @Override
+    public ParcelFileDescriptor setWallpaper(String name, String callingPackage, Bundle extras,
+            int which) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
+
+        if (which == 0) {
+            return null;
+        }
+
         if (!isWallpaperSupported(callingPackage)) {
             return null;
         }
+
         synchronized (mLock) {
             if (DEBUG) Slog.v(TAG, "setWallpaper");
             int userId = UserHandle.getCallingUserId();
             WallpaperData wallpaper = getWallpaperSafeLocked(userId);
             final long ident = Binder.clearCallingIdentity();
             try {
-                ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper);
+                ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
                 if (pfd != null) {
                     wallpaper.imageWallpaperPending = true;
                 }
@@ -870,7 +898,8 @@
         }
     }
 
-    ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper) {
+    ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper,
+            Bundle extras) {
         if (name == null) name = "";
         try {
             File dir = getWallpaperDir(wallpaper.userId);
@@ -888,6 +917,14 @@
                 return null;
             }
             wallpaper.name = name;
+            wallpaper.wallpaperId = makeWallpaperIdLocked();
+            if (extras != null) {
+                extras.putInt(WallpaperManager.EXTRA_NEW_WALLPAPER_ID, wallpaper.wallpaperId);
+            }
+            if (DEBUG) {
+                Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
+                        + " name=" + name);
+            }
             return fd;
         } catch (FileNotFoundException e) {
             Slog.w(TAG, "Error setting wallpaper", e);
@@ -1156,6 +1193,7 @@
             out.startDocument(null, true);
 
             out.startTag(null, "wp");
+            out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
             out.attribute(null, "width", Integer.toString(wallpaper.width));
             out.attribute(null, "height", Integer.toString(wallpaper.height));
             if (wallpaper.padding.left != 0) {
@@ -1184,13 +1222,7 @@
             stream.close();
             journal.commit();
         } catch (IOException e) {
-            try {
-                if (stream != null) {
-                    stream.close();
-                }
-            } catch (IOException ex) {
-                // Ignore
-            }
+            IoUtils.closeQuietly(stream);
             journal.rollback();
         }
     }
@@ -1259,6 +1291,16 @@
                 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();
+                        }
+
                         wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
                         wallpaper.height = Integer.parseInt(parser
                                 .getAttributeValue(null, "height"));
@@ -1301,19 +1343,21 @@
         } catch (IndexOutOfBoundsException e) {
             Slog.w(TAG, "failed parsing " + file + " " + e);
         }
-        try {
-            if (stream != null) {
-                stream.close();
-            }
-        } catch (IOException e) {
-            // Ignore
-        }
+        IoUtils.closeQuietly(stream);
 
         if (!success) {
             wallpaper.width = -1;
             wallpaper.height = -1;
             wallpaper.padding.set(0, 0, 0, 0);
             wallpaper.name = "";
+        } else {
+            if (wallpaper.wallpaperId <= 0) {
+                wallpaper.wallpaperId = makeWallpaperIdLocked();
+                if (DEBUG) {
+                    Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId
+                            + "); now " + wallpaper.wallpaperId);
+                }
+            }
         }
 
         // We always want to have some reasonable width hint.
@@ -1346,6 +1390,7 @@
         synchronized (mLock) {
             loadSettingsLocked(0);
             wallpaper = mWallpaperMap.get(0);
+            wallpaper.wallpaperId = makeWallpaperIdLocked();    // always bump id at restore
             if (wallpaper.nextWallpaperComponent != null
                     && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
                 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
@@ -1366,7 +1411,8 @@
                     if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
                     success = restoreNamedResourceLocked(wallpaper);
                 }
-                if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
+                if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success
+                        + " id=" + wallpaper.wallpaperId);
                 if (success) {
                     bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
                             wallpaper, null);
@@ -1442,16 +1488,10 @@
                 } catch (IOException e) {
                     Slog.e(TAG, "IOException while restoring wallpaper ", e);
                 } finally {
-                    if (res != null) {
-                        try {
-                            res.close();
-                        } catch (IOException ex) {}
-                    }
+                    IoUtils.closeQuietly(res);
                     if (fos != null) {
                         FileUtils.sync(fos);
-                        try {
-                            fos.close();
-                        } catch (IOException ex) {}
+                        IoUtils.closeQuietly(fos);
                     }
                 }
             }
@@ -1474,7 +1514,8 @@
             pw.println("Current Wallpaper Service state:");
             for (int i = 0; i < mWallpaperMap.size(); i++) {
                 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
-                pw.println(" User " + wallpaper.userId + ":");
+                pw.print(" User "); pw.print(wallpaper.userId);
+                pw.print(": id="); pw.println(wallpaper.wallpaperId);
                 pw.print("  mWidth=");
                     pw.print(wallpaper.width);
                     pw.print(" mHeight=");