1 /* 2 * Copyright (C) 2023 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 17 package com.android.server.wallpaper; 18 19 import static android.app.WallpaperManager.FLAG_LOCK; 20 import static android.app.WallpaperManager.FLAG_SYSTEM; 21 import static android.view.Display.DEFAULT_DISPLAY; 22 23 import static com.android.server.wallpaper.WallpaperDisplayHelper.DisplayData; 24 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER; 25 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_CROP; 26 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_INFO; 27 import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir; 28 import static com.android.server.wallpaper.WallpaperUtils.makeWallpaperIdLocked; 29 30 import android.annotation.Nullable; 31 import android.app.WallpaperColors; 32 import android.app.WallpaperManager; 33 import android.app.WallpaperManager.SetWallpaperFlags; 34 import android.app.backup.WallpaperBackupHelper; 35 import android.content.ComponentName; 36 import android.content.Context; 37 import android.content.pm.PackageManager; 38 import android.content.res.Resources; 39 import android.graphics.Color; 40 import android.os.FileUtils; 41 import android.os.SystemProperties; 42 import android.util.Slog; 43 import android.util.SparseArray; 44 import android.util.Xml; 45 46 import com.android.internal.R; 47 import com.android.internal.annotations.VisibleForTesting; 48 import com.android.internal.util.JournaledFile; 49 import com.android.modules.utils.TypedXmlPullParser; 50 import com.android.modules.utils.TypedXmlSerializer; 51 52 import libcore.io.IoUtils; 53 54 import org.xmlpull.v1.XmlPullParser; 55 import org.xmlpull.v1.XmlPullParserException; 56 57 import java.io.File; 58 import java.io.FileInputStream; 59 import java.io.FileNotFoundException; 60 import java.io.FileOutputStream; 61 import java.io.IOException; 62 import java.io.InputStream; 63 import java.util.HashMap; 64 import java.util.Map; 65 66 /** 67 * Helper for the wallpaper loading / saving / xml parsing 68 * Only meant to be used lock held by WallpaperManagerService 69 * Only meant to be instantiated once by WallpaperManagerService 70 */ 71 class WallpaperDataParser { 72 73 private static final String TAG = WallpaperDataParser.class.getSimpleName(); 74 private static final boolean DEBUG = false; 75 private final ComponentName mImageWallpaper; 76 private final WallpaperDisplayHelper mWallpaperDisplayHelper; 77 private final WallpaperCropper mWallpaperCropper; 78 private final Context mContext; 79 80 private final boolean mIsLockscreenLiveWallpaperEnabled; 81 WallpaperDataParser(Context context, WallpaperDisplayHelper wallpaperDisplayHelper, WallpaperCropper wallpaperCropper)82 WallpaperDataParser(Context context, WallpaperDisplayHelper wallpaperDisplayHelper, 83 WallpaperCropper wallpaperCropper) { 84 mContext = context; 85 mWallpaperDisplayHelper = wallpaperDisplayHelper; 86 mWallpaperCropper = wallpaperCropper; 87 mImageWallpaper = ComponentName.unflattenFromString( 88 context.getResources().getString(R.string.image_wallpaper_component)); 89 mIsLockscreenLiveWallpaperEnabled = 90 SystemProperties.getBoolean("persist.wm.debug.lockscreen_live_wallpaper", true); 91 } 92 makeJournaledFile(int userId)93 private JournaledFile makeJournaledFile(int userId) { 94 final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath(); 95 return new JournaledFile(new File(base), new File(base + ".tmp")); 96 } 97 98 static class WallpaperLoadingResult { 99 100 private final WallpaperData mSystemWallpaperData; 101 102 @Nullable 103 private final WallpaperData mLockWallpaperData; 104 105 private final boolean mSuccess; 106 WallpaperLoadingResult( WallpaperData systemWallpaperData, WallpaperData lockWallpaperData, boolean success)107 private WallpaperLoadingResult( 108 WallpaperData systemWallpaperData, 109 WallpaperData lockWallpaperData, 110 boolean success) { 111 mSystemWallpaperData = systemWallpaperData; 112 mLockWallpaperData = lockWallpaperData; 113 mSuccess = success; 114 } 115 getSystemWallpaperData()116 public WallpaperData getSystemWallpaperData() { 117 return mSystemWallpaperData; 118 } 119 getLockWallpaperData()120 public WallpaperData getLockWallpaperData() { 121 return mLockWallpaperData; 122 } 123 success()124 public boolean success() { 125 return mSuccess; 126 } 127 } 128 129 /** 130 * TODO(b/197814683) adapt comment once flag is removed 131 * 132 * Load the system wallpaper (and the lock wallpaper, if it exists) from disk 133 * @param userId the id of the user for which the wallpaper should be loaded 134 * @param keepDimensionHints if false, parse and set the 135 * {@link DisplayData} width and height for the specified userId 136 * @param wallpaper the wallpaper object to reuse to do the modifications. 137 * If null, a new object will be created. 138 * @param lockWallpaper the lock wallpaper object to reuse to do the modifications. 139 * If null, a new object will be created. 140 * @param which The wallpaper(s) to load. Only has effect if 141 * {@link WallpaperManager#isLockscreenLiveWallpaperEnabled} is true, 142 * otherwise both wallpaper will always be loaded. 143 * @return a {@link WallpaperLoadingResult} object containing the wallpaper data. 144 * This object will contain the {@code wallpaper} and 145 * {@code lockWallpaper} provided as parameters, if they are not null. 146 */ loadSettingsLocked(int userId, boolean keepDimensionHints, WallpaperData wallpaper, WallpaperData lockWallpaper, @SetWallpaperFlags int which)147 public WallpaperLoadingResult loadSettingsLocked(int userId, boolean keepDimensionHints, 148 WallpaperData wallpaper, WallpaperData lockWallpaper, @SetWallpaperFlags int which) { 149 JournaledFile journal = makeJournaledFile(userId); 150 FileInputStream stream = null; 151 File file = journal.chooseForRead(); 152 153 boolean migrateFromOld = wallpaper == null; 154 155 boolean separateLockscreenEngine = mIsLockscreenLiveWallpaperEnabled; 156 boolean loadSystem = !separateLockscreenEngine || (which & FLAG_SYSTEM) != 0; 157 boolean loadLock = !separateLockscreenEngine || (which & FLAG_LOCK) != 0; 158 159 // don't reuse the wallpaper objects in the new version 160 if (separateLockscreenEngine) { 161 wallpaper = null; 162 lockWallpaper = null; 163 } 164 165 if (wallpaper == null && loadSystem) { 166 // Do this once per boot 167 if (migrateFromOld) migrateFromOld(); 168 wallpaper = new WallpaperData(userId, FLAG_SYSTEM); 169 wallpaper.allowBackup = true; 170 if (!wallpaper.cropExists()) { 171 if (wallpaper.sourceExists()) { 172 mWallpaperCropper.generateCrop(wallpaper); 173 } else { 174 Slog.i(TAG, "No static wallpaper imagery; defaults will be shown"); 175 } 176 } 177 } 178 179 final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY); 180 boolean success = false; 181 182 try { 183 stream = new FileInputStream(file); 184 TypedXmlPullParser parser = Xml.resolvePullParser(stream); 185 186 int type; 187 do { 188 type = parser.next(); 189 if (type == XmlPullParser.START_TAG) { 190 String tag = parser.getName(); 191 if (("wp".equals(tag) && loadSystem) 192 || ("kwp".equals(tag) && mIsLockscreenLiveWallpaperEnabled 193 && loadLock)) { 194 195 if ("kwp".equals(tag) && lockWallpaper == null) { 196 lockWallpaper = new WallpaperData(userId, FLAG_LOCK); 197 } 198 WallpaperData wallpaperToParse = 199 "wp".equals(tag) ? wallpaper : lockWallpaper; 200 201 parseWallpaperAttributes(parser, wallpaperToParse, keepDimensionHints); 202 203 String comp = parser.getAttributeValue(null, "component"); 204 wallpaperToParse.nextWallpaperComponent = comp != null 205 ? ComponentName.unflattenFromString(comp) 206 : null; 207 if (wallpaperToParse.nextWallpaperComponent == null 208 || "android".equals(wallpaperToParse.nextWallpaperComponent 209 .getPackageName())) { 210 wallpaperToParse.nextWallpaperComponent = mImageWallpaper; 211 } 212 213 if (DEBUG) { 214 Slog.v(TAG, "mWidth:" + wpdData.mWidth); 215 Slog.v(TAG, "mHeight:" + wpdData.mHeight); 216 Slog.v(TAG, "cropRect:" + wallpaper.cropHint); 217 Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors); 218 Slog.v(TAG, "mName:" + wallpaper.name); 219 Slog.v(TAG, "mNextWallpaperComponent:" 220 + wallpaper.nextWallpaperComponent); 221 } 222 } else if ("kwp".equals(tag) && !mIsLockscreenLiveWallpaperEnabled) { 223 // keyguard-specific wallpaper for this user (legacy code) 224 if (lockWallpaper == null) { 225 lockWallpaper = new WallpaperData(userId, FLAG_LOCK); 226 } 227 parseWallpaperAttributes(parser, lockWallpaper, false); 228 } 229 } 230 } while (type != XmlPullParser.END_DOCUMENT); 231 success = true; 232 } catch (FileNotFoundException e) { 233 Slog.w(TAG, "no current wallpaper -- first boot?"); 234 } catch (NullPointerException e) { 235 Slog.w(TAG, "failed parsing " + file + " " + e); 236 } catch (NumberFormatException e) { 237 Slog.w(TAG, "failed parsing " + file + " " + e); 238 } catch (XmlPullParserException e) { 239 Slog.w(TAG, "failed parsing " + file + " " + e); 240 } catch (IOException e) { 241 Slog.w(TAG, "failed parsing " + file + " " + e); 242 } catch (IndexOutOfBoundsException e) { 243 Slog.w(TAG, "failed parsing " + file + " " + e); 244 } 245 IoUtils.closeQuietly(stream); 246 247 mWallpaperDisplayHelper.ensureSaneWallpaperDisplaySize(wpdData, DEFAULT_DISPLAY); 248 249 if (loadSystem) { 250 if (!success) { 251 wallpaper.cropHint.set(0, 0, 0, 0); 252 wpdData.mPadding.set(0, 0, 0, 0); 253 wallpaper.name = ""; 254 } else { 255 if (wallpaper.wallpaperId <= 0) { 256 wallpaper.wallpaperId = makeWallpaperIdLocked(); 257 if (DEBUG) { 258 Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId 259 + "); now " + wallpaper.wallpaperId); 260 } 261 } 262 } 263 ensureSaneWallpaperData(wallpaper); 264 wallpaper.mWhich = lockWallpaper != null ? FLAG_SYSTEM : FLAG_SYSTEM | FLAG_LOCK; 265 } 266 267 if (loadLock) { 268 if (!success) lockWallpaper = null; 269 if (lockWallpaper != null) { 270 ensureSaneWallpaperData(lockWallpaper); 271 lockWallpaper.mWhich = FLAG_LOCK; 272 } 273 } 274 275 return new WallpaperLoadingResult(wallpaper, lockWallpaper, success); 276 } 277 ensureSaneWallpaperData(WallpaperData wallpaper)278 private void ensureSaneWallpaperData(WallpaperData wallpaper) { 279 // Only overwrite cropHint if the rectangle is invalid. 280 if (wallpaper.cropHint.width() < 0 281 || wallpaper.cropHint.height() < 0) { 282 wallpaper.cropHint.set(0, 0, 0, 0); 283 } 284 } 285 286 migrateFromOld()287 private void migrateFromOld() { 288 // Pre-N, what existed is the one we're now using as the display crop 289 File preNWallpaper = new File(getWallpaperDir(0), WALLPAPER_CROP); 290 // In the very-long-ago, imagery lived with the settings app 291 File originalWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY); 292 File newWallpaper = new File(getWallpaperDir(0), WALLPAPER); 293 294 // Migrations from earlier wallpaper image storage schemas 295 if (preNWallpaper.exists()) { 296 if (!newWallpaper.exists()) { 297 // we've got the 'wallpaper' crop file but not the nominal source image, 298 // so do the simple "just take everything" straight copy of legacy data 299 if (DEBUG) { 300 Slog.i(TAG, "Migrating wallpaper schema"); 301 } 302 FileUtils.copyFile(preNWallpaper, newWallpaper); 303 } // else we're in the usual modern case: both source & crop exist 304 } else if (originalWallpaper.exists()) { 305 // VERY old schema; make sure things exist and are in the right place 306 if (DEBUG) { 307 Slog.i(TAG, "Migrating antique wallpaper schema"); 308 } 309 File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY); 310 if (oldInfo.exists()) { 311 File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO); 312 oldInfo.renameTo(newInfo); 313 } 314 315 FileUtils.copyFile(originalWallpaper, preNWallpaper); 316 originalWallpaper.renameTo(newWallpaper); 317 } 318 } 319 320 @VisibleForTesting parseWallpaperAttributes(TypedXmlPullParser parser, WallpaperData wallpaper, boolean keepDimensionHints)321 void parseWallpaperAttributes(TypedXmlPullParser parser, WallpaperData wallpaper, 322 boolean keepDimensionHints) throws XmlPullParserException { 323 final int id = parser.getAttributeInt(null, "id", -1); 324 if (id != -1) { 325 wallpaper.wallpaperId = id; 326 if (id > WallpaperUtils.getCurrentWallpaperId()) { 327 WallpaperUtils.setCurrentWallpaperId(id); 328 } 329 } else { 330 wallpaper.wallpaperId = makeWallpaperIdLocked(); 331 } 332 333 final DisplayData wpData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY); 334 335 if (!keepDimensionHints) { 336 wpData.mWidth = parser.getAttributeInt(null, "width"); 337 wpData.mHeight = parser.getAttributeInt(null, "height"); 338 } 339 wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0); 340 wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0); 341 wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0); 342 wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0); 343 wpData.mPadding.left = getAttributeInt(parser, "paddingLeft", 0); 344 wpData.mPadding.top = getAttributeInt(parser, "paddingTop", 0); 345 wpData.mPadding.right = getAttributeInt(parser, "paddingRight", 0); 346 wpData.mPadding.bottom = getAttributeInt(parser, "paddingBottom", 0); 347 wallpaper.mWallpaperDimAmount = getAttributeFloat(parser, "dimAmount", 0f); 348 int dimAmountsCount = getAttributeInt(parser, "dimAmountsCount", 0); 349 if (dimAmountsCount > 0) { 350 SparseArray<Float> allDimAmounts = new SparseArray<>(dimAmountsCount); 351 for (int i = 0; i < dimAmountsCount; i++) { 352 int uid = getAttributeInt(parser, "dimUID" + i, 0); 353 float dimValue = getAttributeFloat(parser, "dimValue" + i, 0f); 354 allDimAmounts.put(uid, dimValue); 355 } 356 wallpaper.mUidToDimAmount = allDimAmounts; 357 } 358 int colorsCount = getAttributeInt(parser, "colorsCount", 0); 359 int allColorsCount = getAttributeInt(parser, "allColorsCount", 0); 360 if (allColorsCount > 0) { 361 Map<Integer, Integer> allColors = new HashMap<>(allColorsCount); 362 for (int i = 0; i < allColorsCount; i++) { 363 int colorInt = getAttributeInt(parser, "allColorsValue" + i, 0); 364 int population = getAttributeInt(parser, "allColorsPopulation" + i, 0); 365 allColors.put(colorInt, population); 366 } 367 int colorHints = getAttributeInt(parser, "colorHints", 0); 368 wallpaper.primaryColors = new WallpaperColors(allColors, colorHints); 369 } else if (colorsCount > 0) { 370 Color primary = null, secondary = null, tertiary = null; 371 for (int i = 0; i < colorsCount; i++) { 372 Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0)); 373 if (i == 0) { 374 primary = color; 375 } else if (i == 1) { 376 secondary = color; 377 } else if (i == 2) { 378 tertiary = color; 379 } else { 380 break; 381 } 382 } 383 int colorHints = getAttributeInt(parser, "colorHints", 0); 384 wallpaper.primaryColors = new WallpaperColors(primary, secondary, tertiary, colorHints); 385 } 386 wallpaper.name = parser.getAttributeValue(null, "name"); 387 wallpaper.allowBackup = parser.getAttributeBoolean(null, "backup", false); 388 } 389 getAttributeInt(TypedXmlPullParser parser, String name, int defValue)390 private int getAttributeInt(TypedXmlPullParser parser, String name, int defValue) { 391 return parser.getAttributeInt(null, name, defValue); 392 } 393 getAttributeFloat(TypedXmlPullParser parser, String name, float defValue)394 private float getAttributeFloat(TypedXmlPullParser parser, String name, float defValue) { 395 return parser.getAttributeFloat(null, name, defValue); 396 } 397 saveSettingsLocked(int userId, WallpaperData wallpaper, WallpaperData lockWallpaper)398 void saveSettingsLocked(int userId, WallpaperData wallpaper, WallpaperData lockWallpaper) { 399 JournaledFile journal = makeJournaledFile(userId); 400 FileOutputStream fstream = null; 401 try { 402 fstream = new FileOutputStream(journal.chooseForWrite(), false); 403 TypedXmlSerializer out = Xml.resolveSerializer(fstream); 404 out.startDocument(null, true); 405 406 if (wallpaper != null) { 407 writeWallpaperAttributes(out, "wp", wallpaper); 408 } 409 410 if (lockWallpaper != null) { 411 writeWallpaperAttributes(out, "kwp", lockWallpaper); 412 } 413 414 out.endDocument(); 415 416 fstream.flush(); 417 FileUtils.sync(fstream); 418 fstream.close(); 419 journal.commit(); 420 } catch (IOException e) { 421 IoUtils.closeQuietly(fstream); 422 journal.rollback(); 423 } 424 } 425 426 @VisibleForTesting writeWallpaperAttributes(TypedXmlSerializer out, String tag, WallpaperData wallpaper)427 void writeWallpaperAttributes(TypedXmlSerializer out, String tag, WallpaperData wallpaper) 428 throws IllegalArgumentException, IllegalStateException, IOException { 429 if (DEBUG) { 430 Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId); 431 } 432 final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY); 433 out.startTag(null, tag); 434 out.attributeInt(null, "id", wallpaper.wallpaperId); 435 out.attributeInt(null, "width", wpdData.mWidth); 436 out.attributeInt(null, "height", wpdData.mHeight); 437 438 out.attributeInt(null, "cropLeft", wallpaper.cropHint.left); 439 out.attributeInt(null, "cropTop", wallpaper.cropHint.top); 440 out.attributeInt(null, "cropRight", wallpaper.cropHint.right); 441 out.attributeInt(null, "cropBottom", wallpaper.cropHint.bottom); 442 443 if (wpdData.mPadding.left != 0) { 444 out.attributeInt(null, "paddingLeft", wpdData.mPadding.left); 445 } 446 if (wpdData.mPadding.top != 0) { 447 out.attributeInt(null, "paddingTop", wpdData.mPadding.top); 448 } 449 if (wpdData.mPadding.right != 0) { 450 out.attributeInt(null, "paddingRight", wpdData.mPadding.right); 451 } 452 if (wpdData.mPadding.bottom != 0) { 453 out.attributeInt(null, "paddingBottom", wpdData.mPadding.bottom); 454 } 455 456 out.attributeFloat(null, "dimAmount", wallpaper.mWallpaperDimAmount); 457 int dimAmountsCount = wallpaper.mUidToDimAmount.size(); 458 out.attributeInt(null, "dimAmountsCount", dimAmountsCount); 459 if (dimAmountsCount > 0) { 460 int index = 0; 461 for (int i = 0; i < wallpaper.mUidToDimAmount.size(); i++) { 462 out.attributeInt(null, "dimUID" + index, wallpaper.mUidToDimAmount.keyAt(i)); 463 out.attributeFloat(null, "dimValue" + index, wallpaper.mUidToDimAmount.valueAt(i)); 464 index++; 465 } 466 } 467 468 if (wallpaper.primaryColors != null) { 469 int colorsCount = wallpaper.primaryColors.getMainColors().size(); 470 out.attributeInt(null, "colorsCount", colorsCount); 471 if (colorsCount > 0) { 472 for (int i = 0; i < colorsCount; i++) { 473 final Color wc = wallpaper.primaryColors.getMainColors().get(i); 474 out.attributeInt(null, "colorValue" + i, wc.toArgb()); 475 } 476 } 477 478 int allColorsCount = wallpaper.primaryColors.getAllColors().size(); 479 out.attributeInt(null, "allColorsCount", allColorsCount); 480 if (allColorsCount > 0) { 481 int index = 0; 482 for (Map.Entry<Integer, Integer> entry : wallpaper.primaryColors.getAllColors() 483 .entrySet()) { 484 out.attributeInt(null, "allColorsValue" + index, entry.getKey()); 485 out.attributeInt(null, "allColorsPopulation" + index, entry.getValue()); 486 index++; 487 } 488 } 489 490 out.attributeInt(null, "colorHints", wallpaper.primaryColors.getColorHints()); 491 } 492 493 out.attribute(null, "name", wallpaper.name); 494 if (wallpaper.wallpaperComponent != null 495 && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) { 496 out.attribute(null, "component", 497 wallpaper.wallpaperComponent.flattenToShortString()); 498 } 499 500 if (wallpaper.allowBackup) { 501 out.attributeBoolean(null, "backup", true); 502 } 503 504 out.endTag(null, tag); 505 } 506 507 // Restore the named resource bitmap to both source + crop files restoreNamedResourceLocked(WallpaperData wallpaper)508 boolean restoreNamedResourceLocked(WallpaperData wallpaper) { 509 if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) { 510 String resName = wallpaper.name.substring(4); 511 512 String pkg = null; 513 int colon = resName.indexOf(':'); 514 if (colon > 0) { 515 pkg = resName.substring(0, colon); 516 } 517 518 String ident = null; 519 int slash = resName.lastIndexOf('/'); 520 if (slash > 0) { 521 ident = resName.substring(slash + 1); 522 } 523 524 String type = null; 525 if (colon > 0 && slash > 0 && (slash - colon) > 1) { 526 type = resName.substring(colon + 1, slash); 527 } 528 529 if (pkg != null && ident != null && type != null) { 530 int resId = -1; 531 InputStream res = null; 532 FileOutputStream fos = null; 533 FileOutputStream cos = null; 534 try { 535 Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED); 536 Resources r = c.getResources(); 537 resId = r.getIdentifier(resName, null, null); 538 if (resId == 0) { 539 Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type 540 + " ident=" + ident); 541 return false; 542 } 543 544 res = r.openRawResource(resId); 545 if (wallpaper.getWallpaperFile().exists()) { 546 wallpaper.getWallpaperFile().delete(); 547 wallpaper.getCropFile().delete(); 548 } 549 fos = new FileOutputStream(wallpaper.getWallpaperFile()); 550 cos = new FileOutputStream(wallpaper.getCropFile()); 551 552 byte[] buffer = new byte[32768]; 553 int amt; 554 while ((amt = res.read(buffer)) > 0) { 555 fos.write(buffer, 0, amt); 556 cos.write(buffer, 0, amt); 557 } 558 // mWallpaperObserver will notice the close and send the change broadcast 559 560 Slog.v(TAG, "Restored wallpaper: " + resName); 561 return true; 562 } catch (PackageManager.NameNotFoundException e) { 563 Slog.e(TAG, "Package name " + pkg + " not found"); 564 } catch (Resources.NotFoundException e) { 565 Slog.e(TAG, "Resource not found: " + resId); 566 } catch (IOException e) { 567 Slog.e(TAG, "IOException while restoring wallpaper ", e); 568 } finally { 569 IoUtils.closeQuietly(res); 570 if (fos != null) { 571 FileUtils.sync(fos); 572 } 573 if (cos != null) { 574 FileUtils.sync(cos); 575 } 576 IoUtils.closeQuietly(fos); 577 IoUtils.closeQuietly(cos); 578 } 579 } 580 } 581 return false; 582 } 583 } 584