WallpaperBackupHelper.java revision 406abd45471c523aea151f5aca84b008fee02bbe
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.app.backup; 18 19import android.app.WallpaperManager; 20import android.content.Context; 21import android.graphics.BitmapFactory; 22import android.graphics.Point; 23import android.os.Environment; 24import android.os.ParcelFileDescriptor; 25import android.os.UserHandle; 26import android.util.Slog; 27import android.view.Display; 28import android.view.WindowManager; 29 30import java.io.File; 31 32/** 33 * Helper for backing up / restoring wallpapers. Basically an AbsoluteFileBackupHelper, 34 * but with logic for deciding what to do with restored wallpaper images. 35 * 36 * @hide 37 */ 38public class WallpaperBackupHelper extends FileBackupHelperBase implements BackupHelper { 39 private static final String TAG = "WallpaperBackupHelper"; 40 private static final boolean DEBUG = false; 41 42 // If 'true', then apply an acceptable-size heuristic at restore time, dropping back 43 // to the factory default wallpaper if the restored one differs "too much" from the 44 // device's preferred wallpaper image dimensions. 45 private static final boolean REJECT_OUTSIZED_RESTORE = false; 46 47 // This path must match what the WallpaperManagerService uses 48 // TODO: Will need to change if backing up non-primary user's wallpaper 49 public static final String WALLPAPER_IMAGE = 50 new File(Environment.getUserSystemDirectory(UserHandle.USER_OWNER), 51 "wallpaper").getAbsolutePath(); 52 public static final String WALLPAPER_INFO = 53 new File(Environment.getUserSystemDirectory(UserHandle.USER_OWNER), 54 "wallpaper_info.xml").getAbsolutePath(); 55 // Use old keys to keep legacy data compatibility and avoid writing two wallpapers 56 public static final String WALLPAPER_IMAGE_KEY = 57 "/data/data/com.android.settings/files/wallpaper"; 58 public static final String WALLPAPER_INFO_KEY = "/data/system/wallpaper_info.xml"; 59 60 // Stage file - should be adjacent to the WALLPAPER_IMAGE location. The wallpapers 61 // will be saved to this file from the restore stream, then renamed to the proper 62 // location if it's deemed suitable. 63 // TODO: Will need to change if backing up non-primary user's wallpaper 64 private static final String STAGE_FILE = 65 new File(Environment.getUserSystemDirectory(UserHandle.USER_OWNER), 66 "wallpaper-tmp").getAbsolutePath(); 67 68 Context mContext; 69 String[] mFiles; 70 String[] mKeys; 71 double mDesiredMinWidth; 72 double mDesiredMinHeight; 73 74 /** 75 * Construct a helper for backing up / restoring the files at the given absolute locations 76 * within the file system. 77 * 78 * @param context 79 * @param files 80 */ 81 public WallpaperBackupHelper(Context context, String[] files, String[] keys) { 82 super(context); 83 84 mContext = context; 85 mFiles = files; 86 mKeys = keys; 87 88 final WindowManager wm = 89 (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 90 final WallpaperManager wpm = 91 (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE); 92 final Display d = wm.getDefaultDisplay(); 93 final Point size = new Point(); 94 d.getSize(size); 95 mDesiredMinWidth = size.x; 96 mDesiredMinHeight = (double) wpm.getDesiredMinimumHeight(); 97 98 if (mDesiredMinHeight <= 0) { 99 mDesiredMinHeight = size.y; 100 } 101 102 if (DEBUG) { 103 Slog.d(TAG, "dmW=" + mDesiredMinWidth + " dmH=" + mDesiredMinHeight); 104 } 105 } 106 107 /** 108 * Based on oldState, determine which of the files from the application's data directory 109 * need to be backed up, write them to the data stream, and fill in newState with the 110 * state as it exists now. 111 */ 112 public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 113 ParcelFileDescriptor newState) { 114 performBackup_checked(oldState, data, newState, mFiles, mKeys); 115 } 116 117 /** 118 * Restore one absolute file entity from the restore stream. If we're restoring the 119 * magic wallpaper file, take specific action to determine whether it is suitable for 120 * the current device. 121 */ 122 public void restoreEntity(BackupDataInputStream data) { 123 final String key = data.getKey(); 124 if (isKeyInList(key, mKeys)) { 125 if (key.equals(WALLPAPER_IMAGE_KEY)) { 126 // restore the file to the stage for inspection 127 File f = new File(STAGE_FILE); 128 if (writeFile(f, data)) { 129 130 // Preflight the restored image's dimensions without loading it 131 BitmapFactory.Options options = new BitmapFactory.Options(); 132 options.inJustDecodeBounds = true; 133 BitmapFactory.decodeFile(STAGE_FILE, options); 134 135 if (DEBUG) Slog.d(TAG, "Restoring wallpaper image w=" + options.outWidth 136 + " h=" + options.outHeight); 137 138 if (REJECT_OUTSIZED_RESTORE) { 139 // We accept any wallpaper that is at least as wide as our preference 140 // (i.e. wide enough to fill the screen), and is within a comfortable 141 // factor of the target height, to avoid significant clipping/scaling/ 142 // letterboxing. 143 final double heightRatio = mDesiredMinHeight / options.outHeight; 144 if (options.outWidth < mDesiredMinWidth 145 || heightRatio <= 0 146 || heightRatio >= 1.33) { 147 // Not wide enough for the screen, or too short/tall to be a good fit 148 // for the height of the screen, broken image file, or the system's 149 // desires for wallpaper size are in a bad state. Probably one of the 150 // first two. 151 Slog.i(TAG, "Restored image dimensions (w=" 152 + options.outWidth + ", h=" + options.outHeight 153 + ") too far off target (tw=" 154 + mDesiredMinWidth + ", th=" + mDesiredMinHeight 155 + "); falling back to default wallpaper."); 156 f.delete(); 157 return; 158 } 159 } 160 161 // We passed the acceptable-dimensions test (if any), so we're going to 162 // use the restored image. 163 // TODO: spin a service to copy the restored image to sd/usb storage, 164 // since it does not exist anywhere other than the private wallpaper 165 // file. 166 Slog.d(TAG, "Applying restored wallpaper image."); 167 f.renameTo(new File(WALLPAPER_IMAGE)); 168 } 169 } else if (key.equals(WALLPAPER_INFO_KEY)) { 170 // XML file containing wallpaper info 171 File f = new File(WALLPAPER_INFO); 172 writeFile(f, data); 173 } 174 } 175 } 176} 177