Merge "Don't back up wallpapers that we've been told not to" into nyc-dev
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 2fc6533..a42aed6 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -43,7 +43,8 @@
      * new wallpaper content is ready to display.
      */
     ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
-            in Rect cropHint, out Bundle extras, int which, IWallpaperManagerCallback completion);
+            in Rect cropHint, boolean allowBackup, out Bundle extras, int which,
+            IWallpaperManagerCallback completion);
 
     /**
      * Set the live wallpaper. This only affects the system wallpaper.
@@ -125,6 +126,11 @@
     boolean isWallpaperSettingAllowed(in String callingPackage);
 
     /*
+     * Backup: is the current system wallpaper image eligible for off-device backup?
+     */
+    boolean isWallpaperBackupEligible(int userId);
+
+    /*
      * Keyguard: register a callback for being notified that lock-state relevant
      * wallpaper content has changed.
      */
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 72b9318..18a5593 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1,5 +1,5 @@
 /*
-h * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -875,7 +875,7 @@
             /* Set the wallpaper to the default values */
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
                     "res:" + resources.getResourceName(resid),
-                    mContext.getOpPackageName(), null, result, which, completion);
+                    mContext.getOpPackageName(), null, false, result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
                 boolean ok = false;
@@ -985,7 +985,8 @@
         final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName(), visibleCropHint, result, which, completion);
+                    mContext.getOpPackageName(), visibleCropHint, allowBackup,
+                    result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
@@ -1102,7 +1103,8 @@
         final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName(), visibleCropHint, result, which, completion);
+                    mContext.getOpPackageName(), visibleCropHint, allowBackup,
+                    result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
@@ -1565,6 +1567,25 @@
         }
     }
 
+    /**
+     * Is the current system wallpaper eligible for backup?
+     *
+     * Only the OS itself may use this method.
+     * @hide
+     */
+    public boolean isWallpaperBackupEligible() {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return false;
+        }
+        try {
+            return sGlobals.mService.isWallpaperBackupEligible(mContext.getUserId());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception querying wallpaper backup eligibility: " + e.getMessage());
+        }
+        return false;
+    }
+
     // Private completion callback for setWallpaper() synchronization
     private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
         final CountDownLatch mLatch;
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 2d12fcd..3e45309 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -76,26 +76,6 @@
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) throws IOException {
-        // We only back up the data under the current "wallpaper" schema with metadata
-        IWallpaperManager wallpaper = (IWallpaperManager)ServiceManager.getService(
-                Context.WALLPAPER_SERVICE);
-        String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
-        String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
-        if (wallpaper != null) {
-            try {
-                final String wallpaperName = wallpaper.getName();
-                if (wallpaperName != null && wallpaperName.length() > 0) {
-                    // When the wallpaper has a name, back up the info by itself.
-                    // TODO: Don't rely on the innards of the service object like this!
-                    // TODO: Send a delete for any stored wallpaper image in this case?
-                    files = new String[] { WALLPAPER_INFO };
-                    keys = new String[] { WALLPAPER_INFO_KEY };
-                }
-            } catch (RemoteException re) {
-                Slog.e(TAG, "Couldn't get wallpaper name\n" + re);
-            }
-        }
-        addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this, files, keys));
         addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
         addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
         addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
@@ -107,30 +87,20 @@
 
     @Override
     public void onFullBackup(FullBackupDataOutput data) throws IOException {
-        // At present we back up only the wallpaper
-        fullWallpaperBackup(data);
-    }
-
-    private void fullWallpaperBackup(FullBackupDataOutput output) {
-        // Back up the data files directly.  We do them in this specific order --
-        // info file followed by image -- because then we need take no special
-        // steps during restore; the restore will happen properly when the individual
-        // files are restored piecemeal.
-        FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null,
-                WALLPAPER_INFO_DIR, WALLPAPER_INFO, output);
-        FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null,
-                WALLPAPER_IMAGE_DIR, WALLPAPER_IMAGE, output);
+        // At present we don't back up anything
     }
 
     @Override
     public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
             throws IOException {
+        // Slot in a restore helper for the older wallpaper backup schema to support restore
+        // from devices still generating data in that format.
         mWallpaperHelper = new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
                 new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} );
         addHelper(WALLPAPER_HELPER, mWallpaperHelper);
 
-        // On restore, we also support a previous data schema "system_files"
+        // On restore, we also support a long-ago wallpaper data schema "system_files"
         addHelper("system_files", new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE },
                 new String[] { WALLPAPER_IMAGE_KEY} ));
diff --git a/packages/WallpaperBackup/Android.mk b/packages/WallpaperBackup/Android.mk
new file mode 100644
index 0000000..cf04249
--- /dev/null
+++ b/packages/WallpaperBackup/Android.mk
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2016 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.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PACKAGE_NAME := WallpaperBackup
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := false
+
+include $(BUILD_PACKAGE)
+
+########################
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/packages/WallpaperBackup/AndroidManifest.xml b/packages/WallpaperBackup/AndroidManifest.xml
new file mode 100644
index 0000000..b8cea20
--- /dev/null
+++ b/packages/WallpaperBackup/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.wallpaperbackup"
+    android:sharedUserId="android.uid.system" >
+
+    <application android:allowClearUserData="false"
+                 android:process="system"
+                 android:killAfterRestore="false"
+                 android:allowBackup="true"
+                 android:backupAgent=".WallpaperBackupAgent"
+                 android:fullBackupOnly="true" >
+    </application>
+</manifest>
diff --git a/packages/WallpaperBackup/proguard.flags b/packages/WallpaperBackup/proguard.flags
new file mode 100644
index 0000000..247e6ef
--- /dev/null
+++ b/packages/WallpaperBackup/proguard.flags
@@ -0,0 +1 @@
+-keep class com.android.wallpaperbackup.WallpaperBackupAgent
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
new file mode 100644
index 0000000..2f79079
--- /dev/null
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2016 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaperbackup;
+
+import android.app.WallpaperManager;
+import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.FullBackupDataOutput;
+import android.content.Context;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.system.Os;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class WallpaperBackupAgent extends BackupAgent {
+    private static final String TAG = "WallpaperBackup";
+    private static final boolean DEBUG = false;
+
+    // NB: must be kept in sync with WallpaperManagerService but has no
+    // compile-time visiblity.
+
+    // Target filenames within the system's wallpaper directory
+    static final String WALLPAPER = "wallpaper_orig";
+    static final String WALLPAPER_INFO = "wallpaper_info.xml";
+
+    // Names of our local-data stage files/links
+    static final String IMAGE_STAGE = "wallpaper-stage";
+    static final String INFO_STAGE = "wallpaper-info-stage";
+    static final String EMPTY_SENTINEL = "empty";
+
+    private File mWallpaperInfo;    // wallpaper metadata file
+    private File mWallpaperFile;    // primary wallpaper image file
+
+    private WallpaperManager mWm;
+
+    @Override
+    public void onCreate() {
+        if (DEBUG) {
+            Slog.v(TAG, "onCreate()");
+        }
+
+        File wallpaperDir = Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM);
+        mWallpaperInfo = new File(wallpaperDir, WALLPAPER_INFO);
+        mWallpaperFile = new File(wallpaperDir, WALLPAPER);
+        mWm = (WallpaperManager) getSystemService(Context.WALLPAPER_SERVICE);
+    }
+
+    @Override
+    public void onFullBackup(FullBackupDataOutput data) throws IOException {
+        // To avoid data duplication and disk churn, use links as the stage.
+        final File filesDir = getFilesDir();
+        final File infoStage = new File(filesDir, INFO_STAGE);
+        final File imageStage = new File (filesDir, IMAGE_STAGE);
+        final File empty = new File (filesDir, EMPTY_SENTINEL);
+
+        try {
+            // We always back up this 'empty' file to ensure that the absence of
+            // storable wallpaper imagery still produces a non-empty backup data
+            // stream, otherwise it'd simply be ignored in preflight.
+            FileOutputStream touch = new FileOutputStream(empty);
+            touch.close();
+            fullBackupFile(empty, data);
+
+            // only back up the wallpaper if we've been told it's allowed
+            if (mWm.isWallpaperBackupEligible()) {
+                if (DEBUG) {
+                    Slog.v(TAG, "Wallpaper is backup-eligible; linking & writing");
+                }
+                Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath());
+                fullBackupFile(infoStage, data);
+                Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath());
+                fullBackupFile(imageStage, data);
+            } else {
+                if (DEBUG) {
+                    Slog.v(TAG, "Wallpaper not backup-eligible; writing no data");
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Unable to back up wallpaper: " + e.getMessage());
+        } finally {
+            if (DEBUG) {
+                Slog.v(TAG, "Removing backup stage links");
+            }
+            infoStage.delete();
+            imageStage.delete();
+        }
+    }
+
+    // We use the default onRestoreFile() implementation that will recreate our stage files,
+    // then postprocess in onRestoreFinished() to move them on top of the live data.
+    //
+    // NOTE: this relies on our local files dir being on the same filesystem as the live
+    // system wallpaper data.  If this is not the case then an actual copy operation will
+    // be needed.
+    @Override
+    public void onRestoreFinished() {
+        if (DEBUG) {
+            Slog.v(TAG, "onRestoreFinished()");
+        }
+        final File infoStage = new File(getFilesDir(), INFO_STAGE);
+        final File imageStage = new File (getFilesDir(), IMAGE_STAGE);
+
+        try {
+            // It is valid for the imagery to be absent; it means that we were not permitted
+            // to back up the original image on the source device.
+            if (imageStage.exists()) {
+                if (DEBUG) {
+                    Slog.v(TAG, "Got restored wallpaper; renaming into place");
+                }
+                // Rename the image file into place last because that is the trigger for
+                // the wallpaper observer to generate a new crop/scale
+                Os.rename(infoStage.getCanonicalPath(), mWallpaperInfo.getCanonicalPath());
+                Os.rename(imageStage.getCanonicalPath(), mWallpaperFile.getCanonicalPath());
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage());
+            mWm.clearWallpaper(WallpaperManager.FLAG_SYSTEM, UserHandle.USER_SYSTEM);
+        } finally {
+            // These "should" not exist because of the renames, but make sure
+            // in case of errors/exceptions/etc.
+            if (DEBUG) {
+                Slog.v(TAG, "Removing restore stage files");
+            }
+            infoStage.delete();
+            imageStage.delete();
+        }
+    }
+
+    //
+    // Key/value API: abstract, so required, but not used
+    //
+
+    @Override
+    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) throws IOException {
+        // Intentionally blank
+    }
+
+    @Override
+    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+            throws IOException {
+        // Intentionally blank
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 91b6914..d6ace91 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -34,7 +34,6 @@
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
-import android.app.backup.BackupManager;
 import android.app.backup.WallpaperBackupHelper;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -61,6 +60,7 @@
 import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
+import android.os.Process;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -205,7 +205,8 @@
             if (path == null) {
                 return;
             }
-            final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
+            final boolean moved = (event == MOVED_TO);
+            final boolean written = (event == CLOSE_WRITE || moved);
             final File changedFile = new File(mWallpaperDir, path);
 
             // System and system+lock changes happen on the system wallpaper input file;
@@ -224,13 +225,6 @@
                         + " written=" + written);
             }
             synchronized (mLock) {
-                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 (sysWallpaperChanged || lockWallpaperChanged) {
                     notifyCallbacksLocked(wallpaper);
                     if (wallpaper.wallpaperComponent == null
@@ -244,6 +238,14 @@
                             if (DEBUG) {
                                 Slog.v(TAG, "Wallpaper written; generating crop");
                             }
+                            if (moved) {
+                                // This is a restore, so generate the crop using any just-restored new
+                                // crop guidelines, making sure to preserve our local dimension hints.
+                                if (DEBUG) {
+                                    Slog.v(TAG, "moved-to, therefore restore; reloading metadata");
+                                }
+                                loadSettingsLocked(wallpaper.userId, true);
+                            }
                             generateCrop(wallpaper);
                             if (DEBUG) {
                                 Slog.v(TAG, "Crop done; invoking completion callback");
@@ -491,6 +493,11 @@
         IWallpaperManagerCallback setComplete;
 
         /**
+         * Is the OS allowed to back up this wallpaper imagery?
+         */
+        boolean allowBackup;
+
+        /**
          * Resource name if using a picture from the wallpaper gallery
          */
         String name = "";
@@ -811,7 +818,7 @@
         mMonitor = new MyPackageMonitor();
         mMonitor.register(context, null, UserHandle.ALL, true);
         getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
-        loadSettingsLocked(UserHandle.USER_SYSTEM);
+        loadSettingsLocked(UserHandle.USER_SYSTEM, false);
     }
 
     private static File getWallpaperDir(int userId) {
@@ -1024,7 +1031,7 @@
             wallpaper = mWallpaperMap.get(userId);
             if (wallpaper == null) {
                 // Might need to bring it in the first time to establish our rewrite
-                loadSettingsLocked(userId);
+                loadSettingsLocked(userId, false);
                 wallpaper = mWallpaperMap.get(userId);
             }
         }
@@ -1102,7 +1109,7 @@
                 WallpaperData wd = mWallpaperMap.get(user.id);
                 if (wd == null) {
                     // User hasn't started yet, so load her settings to peek at the wallpaper
-                    loadSettingsLocked(user.id);
+                    loadSettingsLocked(user.id, false);
                     wd = mWallpaperMap.get(user.id);
                 }
                 if (wd != null && name.equals(wd.name)) {
@@ -1235,7 +1242,7 @@
             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(wallpaperUserId);
+                loadSettingsLocked(wallpaperUserId, false);
                 wallpaper = whichSet.get(wallpaperUserId);
                 if (wallpaper == null) {
                     return null;
@@ -1304,7 +1311,8 @@
 
     @Override
     public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
-            Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
+            Rect cropHint, boolean allowBackup, Bundle extras, int which,
+            IWallpaperManagerCallback completion) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
 
         if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
@@ -1342,6 +1350,9 @@
                     wallpaper.whichPending = which;
                     wallpaper.setComplete = completion;
                     wallpaper.cropHint.set(cropHint);
+                    if ((which & FLAG_SYSTEM) != 0) {
+                        wallpaper.allowBackup = allowBackup;
+                    }
                 }
                 return pfd;
             } finally {
@@ -1651,6 +1662,16 @@
         return !um.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER);
     }
 
+    @Override
+    public boolean isWallpaperBackupEligible(int userId) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("Only the system may call isWallpaperBackupEligible");
+        }
+
+        WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
+        return (wallpaper != null) ? wallpaper.allowBackup : false;
+    }
+
     private static JournaledFile makeJournaledFile(int userId) {
         final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
         return new JournaledFile(new File(base), new File(base + ".tmp"));
@@ -1721,6 +1742,11 @@
             out.attribute(null, "component",
                     wallpaper.wallpaperComponent.flattenToShortString());
         }
+
+        if (wallpaper.allowBackup) {
+            out.attribute(null, "backup", "true");
+        }
+
         out.endTag(null, tag);
     }
 
@@ -1764,7 +1790,7 @@
         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);
+            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
@@ -1788,7 +1814,7 @@
         return wallpaper;
     }
 
-    private void loadSettingsLocked(int userId) {
+    private void loadSettingsLocked(int userId, boolean keepDimensionHints) {
         if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
 
         JournaledFile journal = makeJournaledFile(userId);
@@ -1801,6 +1827,7 @@
         WallpaperData wallpaper = mWallpaperMap.get(userId);
         if (wallpaper == null) {
             wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
+            wallpaper.allowBackup = true;
             mWallpaperMap.put(userId, wallpaper);
             if (!wallpaper.cropExists()) {
                 generateCrop(wallpaper);
@@ -1819,7 +1846,7 @@
                     String tag = parser.getName();
                     if ("wp".equals(tag)) {
                         // Common to system + lock wallpapers
-                        parseWallpaperAttributes(parser, wallpaper);
+                        parseWallpaperAttributes(parser, wallpaper, keepDimensionHints);
 
                         // A system wallpaper might also be a live wallpaper
                         String comp = parser.getAttributeValue(null, "component");
@@ -1848,7 +1875,7 @@
                                     WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
                             mLockWallpaperMap.put(userId, lockWallpaper);
                         }
-                        parseWallpaperAttributes(parser, lockWallpaper);
+                        parseWallpaperAttributes(parser, lockWallpaper, false);
                     }
                 }
             } while (type != XmlPullParser.END_DOCUMENT);
@@ -1909,7 +1936,8 @@
         }
     }
 
-    private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper) {
+    private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper,
+            boolean keepDimensionHints) {
         final String idString = parser.getAttributeValue(null, "id");
         if (idString != null) {
             final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
@@ -1920,9 +1948,11 @@
             wallpaper.wallpaperId = makeWallpaperIdLocked();
         }
 
-        wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
-        wallpaper.height = Integer.parseInt(parser
-                .getAttributeValue(null, "height"));
+        if (!keepDimensionHints) {
+            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);
@@ -1932,6 +1962,7 @@
         wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
         wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
         wallpaper.name = parser.getAttributeValue(null, "name");
+        wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
     }
 
     private int getMaximumSizeDimension() {
@@ -1952,9 +1983,10 @@
         WallpaperData wallpaper = null;
         boolean success = false;
         synchronized (mLock) {
-            loadSettingsLocked(UserHandle.USER_SYSTEM);
+            loadSettingsLocked(UserHandle.USER_SYSTEM, false);
             wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
             wallpaper.wallpaperId = makeWallpaperIdLocked();    // always bump id at restore
+            wallpaper.allowBackup = true;   // by definition if it was restored
             if (wallpaper.nextWallpaperComponent != null
                     && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
                 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,