1.长按home页,会弹出切换界面
点击Wallpaper 进入应用中 这里的应用为 com.android.wallpaperpicker/.WallpaperPickerActivity
packages\apps\WallpaperPicker\src\com\android\wallpaperpicker\WallpaperPickerActivity.java
public class WallpaperPickerActivity extends WallpaperCropActivity implements OnClickListener, OnLongClickListener, ActionMode.Callback {
如果选中了具体的 wallpaper set按钮会显示出来
@Override public void onClick(View v) { if (mActionMode != null) { // When CAB is up, clicking toggles the item instead if (v.isLongClickable()) { onLongClick(v); } return; } WallpaperTileInfo info = (WallpaperTileInfo) v.getTag(); if (info.isSelectable() && v.getVisibility() == View.VISIBLE) { selectTile(v); setWallpaperButtonEnabled(true); } info.onClick(this); }
public void setWallpaperButtonEnabled(boolean enabled) { mSetWallpaperButton.setEnabled(enabled); }
mSetWallpaperButton在 WallpaperCropActivity里定义 点击事件为
packages\apps\WallpaperPicker\src\com\android\wallpaperpicker\WallpaperCropActivity.java
final ActionBar actionBar = getActionBar(); actionBar.setCustomView(R.layout.actionbar_set_wallpaper); actionBar.getCustomView().setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { actionBar.hide(); // Never fade on finish because we return to the app that started us (e.g. // Photos), not the home screen. cropImageAndSetWallpaper(imageUri, null, false /* shouldFadeOutOnFinish */); } });
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public void cropImageAndSetWallpaper(Uri uri, CropAndSetWallpaperTask.OnBitmapCroppedHandler onBitmapCroppedHandler, boolean shouldFadeOutOnFinish) { // Get the crop boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; Display d = getWindowManager().getDefaultDisplay(); Point displaySize = new Point(); d.getSize(displaySize); boolean isPortrait = displaySize.x < displaySize.y; Point defaultWallpaperSize = WallpaperUtils.getDefaultWallpaperSize(getResources(), getWindowManager()); // Get the crop RectF cropRect = mCropView.getCrop(); Point inSize = mCropView.getSourceDimensions(); int cropRotation = mCropView.getImageRotation(); float cropScale = mCropView.getWidth() / (float) cropRect.width(); Matrix rotateMatrix = new Matrix(); rotateMatrix.setRotate(cropRotation); float[] rotatedInSize = new float[] { inSize.x, inSize.y }; rotateMatrix.mapPoints(rotatedInSize); rotatedInSize[0] = Math.abs(rotatedInSize[0]); rotatedInSize[1] = Math.abs(rotatedInSize[1]); // due to rounding errors in the cropview renderer the edges can be slightly offset // therefore we ensure that the boundaries are sanely defined cropRect.left = Math.max(0, cropRect.left); cropRect.right = Math.min(rotatedInSize[0], cropRect.right); cropRect.top = Math.max(0, cropRect.top); cropRect.bottom = Math.min(rotatedInSize[1], cropRect.bottom); // ADJUST CROP WIDTH // Extend the crop all the way to the right, for parallax // (or all the way to the left, in RTL) float extraSpace = ltr ? rotatedInSize[0] - cropRect.right : cropRect.left; // Cap the amount of extra width float maxExtraSpace = defaultWallpaperSize.x / cropScale - cropRect.width(); extraSpace = Math.min(extraSpace, maxExtraSpace); if (ltr) { cropRect.right += extraSpace; } else { cropRect.left -= extraSpace; } // ADJUST CROP HEIGHT if (isPortrait) { cropRect.bottom = cropRect.top + defaultWallpaperSize.y / cropScale; } else { // LANDSCAPE float extraPortraitHeight = defaultWallpaperSize.y / cropScale - cropRect.height(); float expandHeight = Math.min(Math.min(rotatedInSize[1] - cropRect.bottom, cropRect.top), extraPortraitHeight / 2); cropRect.top -= expandHeight; cropRect.bottom += expandHeight; } final int outWidth = (int) Math.round(cropRect.width() * cropScale); final int outHeight = (int) Math.round(cropRect.height() * cropScale); CropAndFinishHandler onEndCrop = new CropAndFinishHandler(new Point(outWidth, outHeight), shouldFadeOutOnFinish); CropAndSetWallpaperTask cropTask = new CropAndSetWallpaperTask( InputStreamProvider.fromUri(this, uri), this, cropRect, cropRotation, outWidth, outHeight, onEndCrop) { @Override protected void onPreExecute() { // Give some feedback so user knows something is happening. mProgressView.setVisibility(View.VISIBLE); } }; if (onBitmapCroppedHandler != null) { cropTask.setOnBitmapCropped(onBitmapCroppedHandler); } DialogUtils.executeCropTaskAfterPrompt(this, cropTask, getOnDialogCancelListener()); }
执行 DialogUtils.executeCropTaskAfterPrompt 设置要设置的范围
packages\apps\WallpaperPicker\src\com\android\wallpaperpicker\common\DialogUtils.java
public static void executeCropTaskAfterPrompt( Context context, final AsyncTask<Integer, ?, ?> cropTask, DialogInterface.OnCancelListener onCancelListener) { if (Utilities.isAtLeastN()) { new AlertDialog.Builder(context) .setTitle(R.string.wallpaper_instructions) .setItems(R.array.which_wallpaper_options, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int selectedItemIndex) { int whichWallpaper; if (selectedItemIndex == 0) { whichWallpaper = WallpaperManagerCompat.FLAG_SET_SYSTEM; } else if (selectedItemIndex == 1) { whichWallpaper = WallpaperManagerCompat.FLAG_SET_LOCK; } else { whichWallpaper = WallpaperManagerCompat.FLAG_SET_SYSTEM | WallpaperManagerCompat.FLAG_SET_LOCK; } cropTask.execute(whichWallpaper); } }) .setOnCancelListener(onCancelListener) .show(); } else { cropTask.execute(WallpaperManagerCompat.FLAG_SET_SYSTEM); } }
packages\apps\WallpaperPicker\src\com\android\wallpaperpicker\common\CropAndSetWallpaperTask.java
public boolean cropBitmap(int whichWallpaper) { Bitmap crop = mStreamProvider.readCroppedBitmap( mCropBounds, mOutWidth, mOutHeight, mRotation); if (crop == null) { return false; } boolean failure = false; // Compress to byte array ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048); if (crop.compress(CompressFormat.JPEG, DEFAULT_COMPRESS_QUALITY, tmpOut)) { // Set the wallpaper try { byte[] outByteArray = tmpOut.toByteArray(); WallpaperManagerCompat.getInstance(mContext).setStream( new ByteArrayInputStream(outByteArray), null, true, whichWallpaper); if (mOnBitmapCroppedHandler != null) { mOnBitmapCroppedHandler.onBitmapCropped(outByteArray); } } catch (IOException e) { Log.w(TAG, "cannot write stream to wallpaper", e); failure = true; } } else { Log.w(TAG, "cannot compress bitmap"); failure = true; } return !failure; // True if any of the operations failed } @Override protected Boolean doInBackground(Integer... whichWallpaper) { return cropBitmap(whichWallpaper[0]); }
调用了WallpaperManagerCompat.getInstance(mContext).setStream(
new ByteArrayInputStream(outByteArray),
null, true, whichWallpaper);
packages\apps\WallpaperPicker\src\com\android\wallpaperpicker\common\WallpaperManagerCompat.java
public static WallpaperManagerCompat getInstance(Context context) { synchronized (sInstanceLock) { if (sInstance == null) { if (Utilities.isAtLeastN()) { sInstance = new WallpaperManagerCompatVN(context.getApplicationContext()); } else { sInstance = new WallpaperManagerCompatV16(context.getApplicationContext()); } } return sInstance; } } public abstract void setStream(InputStream stream, Rect visibleCropHint, boolean allowBackup, int whichWallpaper) throws IOException;
public static boolean isAtLeastN() { // TODO: replace this with a more final implementation. try { WallpaperManager.class.getMethod("getWallpaperFile", int.class); return true; } catch (NoSuchMethodException e) { return false; } }
frameworks\base\core\java\android\app\WallpaperManager.java
@RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public ParcelFileDescriptor getWallpaperFile(@SetWallpaperFlags int which) { return getWallpaperFile(which, mContext.getUserId()); }
所以实例化的是WallpaperManagerCompatVN
@Override public void setStream(final InputStream data, Rect visibleCropHint, boolean allowBackup, int whichWallpaper) throws IOException { try { // TODO: use mWallpaperManager.setStream(data, visibleCropHint, allowBackup, which) // without needing reflection. Method setStream = WallpaperManager.class.getMethod("setStream", InputStream.class, Rect.class, boolean.class, int.class); setStream.invoke(mWallpaperManager, data, visibleCropHint, allowBackup, whichWallpaper); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { // Fall back to previous implementation (set both) super.setStream(data, visibleCropHint, allowBackup, whichWallpaper); } }
frameworks\base\core\java\android\app\WallpaperManager.java
@RequiresPermission(android.Manifest.permission.SET_WALLPAPER) 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"); throw new RuntimeException(new DeadSystemException()); } final Bundle result = new Bundle(); final WallpaperSetCompletion completion = new WallpaperSetCompletion(); try { ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null, mContext.getOpPackageName(), visibleCropHint, allowBackup, result, which, completion, mContext.getUserId()); if (fd != null) { FileOutputStream fos = null; try { fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); copyStreamToWallpaperFile(bitmapData, fos); fos.close(); completion.waitForCompletion(); } finally { IoUtils.closeQuietly(fos); } } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0); }
调用sGlobals.mService.setWallpaper
private static class Globals extends IWallpaperManagerCallback.Stub { private final IWallpaperManager mService;
转入WallpaperManagerService frameworks\base\services\core\java\com\android\server\wallpaper\WallpaperManagerService.java
@Override public ParcelFileDescriptor setWallpaper(String name, String callingPackage, Rect cropHint, boolean allowBackup, Bundle extras, int which, IWallpaperManagerCallback completion, int userId) { userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId, false /* all */, true /* full */, "changing wallpaper", null /* pkg */); checkPermission(android.Manifest.permission.SET_WALLPAPER); if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) { final String msg = "Must specify a valid wallpaper category to set"; Slog.e(TAG, msg); throw new IllegalArgumentException(msg); } if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) { return null; } // "null" means the no-op crop, preserving the full input image if (cropHint == null) { cropHint = new Rect(0, 0, 0, 0); } else { if (cropHint.isEmpty() || cropHint.left < 0 || cropHint.top < 0) { throw new IllegalArgumentException("Invalid crop rect supplied: " + cropHint); } } synchronized (mLock) { if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which)); WallpaperData wallpaper; /* If we're setting system but not lock, and lock is currently sharing the system * wallpaper, we need to migrate that image over to being lock-only before * the caller here writes new bitmap data. */ if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) { if (DEBUG) { Slog.i(TAG, "Migrating system->lock to preserve"); } migrateSystemToLockWallpaperLocked(userId); } 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); wallpaper.allowBackup = allowBackup; } return pfd; } finally { Binder.restoreCallingIdentity(ident); } } }
wallpaper = getWallpaperSafeLocked(userId, which);
/** * Sometimes it is expected the wallpaper map may not have a user's data. E.g. This could * happen during user switch. The async user switch observer may not have received * the event yet. We use this safe method when we don't care about this ordering and just * want to update the data. The data is going to be applied when the user switch observer * is eventually executed. * * Important: this method loads settings to initialize the given user's wallpaper data if * there is no current in-memory state. */ 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_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, 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 // it now. if (wallpaper == null) { if (which == FLAG_LOCK) { wallpaper = new WallpaperData(userId, WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); mLockWallpaperMap.put(userId, wallpaper); ensureSaneWallpaperData(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); ensureSaneWallpaperData(wallpaper); } } } return wallpaper; }
private void loadSettingsLocked(int userId, boolean keepDimensionHints) { JournaledFile journal = makeJournaledFile(userId); FileInputStream stream = null; File file = journal.chooseForRead(); WallpaperData wallpaper = mWallpaperMap.get(userId); if (wallpaper == null) { // Do this once per boot migrateFromOld(); wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP); wallpaper.allowBackup = true; mWallpaperMap.put(userId, wallpaper); if (!wallpaper.cropExists()) { if (wallpaper.sourceExists()) { generateCrop(wallpaper); } else { Slog.i(TAG, "No static wallpaper imagery; defaults will be shown"); } } } boolean success = false; try { stream = new FileInputStream(file); XmlPullParser parser = Xml.newPullParser(); parser.setInput(stream, StandardCharsets.UTF_8.name()); int type; do { type = parser.next(); if (type == XmlPullParser.START_TAG) { String tag = parser.getName(); if ("wp".equals(tag)) { // Common to system + lock wallpapers parseWallpaperAttributes(parser, wallpaper, keepDimensionHints); // A system wallpaper might also be a live wallpaper String comp = parser.getAttributeValue(null, "component"); wallpaper.nextWallpaperComponent = comp != null ? ComponentName.unflattenFromString(comp) : null; if (wallpaper.nextWallpaperComponent == null || "android".equals(wallpaper.nextWallpaperComponent .getPackageName())) { wallpaper.nextWallpaperComponent = mImageWallpaper; } if (DEBUG) { Slog.v(TAG, "mWidth:" + wallpaper.width); Slog.v(TAG, "mHeight:" + wallpaper.height); Slog.v(TAG, "cropRect:" + wallpaper.cropHint); Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors); Slog.v(TAG, "mName:" + wallpaper.name); 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, false); } } } while (type != XmlPullParser.END_DOCUMENT); success = true; } catch (FileNotFoundException e) { Slog.w(TAG, "no current wallpaper -- first boot?"); } catch (NullPointerException e) { Slog.w(TAG, "failed parsing " + file + " " + e); } catch (NumberFormatException e) { Slog.w(TAG, "failed parsing " + file + " " + e); } catch (XmlPullParserException e) { Slog.w(TAG, "failed parsing " + file + " " + e); } catch (IOException e) { Slog.w(TAG, "failed parsing " + file + " " + e); } catch (IndexOutOfBoundsException e) { Slog.w(TAG, "failed parsing " + file + " " + e); } IoUtils.closeQuietly(stream); if (!success) { wallpaper.width = -1; wallpaper.height = -1; wallpaper.cropHint.set(0, 0, 0, 0); wallpaper.padding.set(0, 0, 0, 0); wallpaper.name = ""; mLockWallpaperMap.remove(userId); } else { if (wallpaper.wallpaperId <= 0) { wallpaper.wallpaperId = makeWallpaperIdLocked(); if (DEBUG) { Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId + "); now " + wallpaper.wallpaperId); } } } ensureSaneWallpaperData(wallpaper); WallpaperData lockWallpaper = mLockWallpaperMap.get(userId); if (lockWallpaper != null) { ensureSaneWallpaperData(lockWallpaper); } }
ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper, Bundle extras) { if (name == null) name = ""; try { File dir = getWallpaperDir(wallpaper.userId); if (!dir.exists()) { dir.mkdir(); FileUtils.setPermissions( dir.getPath(), FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1); } ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile, MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE); if (!SELinux.restorecon(wallpaper.wallpaperFile)) { return null; } wallpaper.name = name; wallpaper.wallpaperId = makeWallpaperIdLocked(); if (extras != null) { extras.putInt(WallpaperManager.EXTRA_NEW_WALLPAPER_ID, wallpaper.wallpaperId); } // Nullify field to require new computation wallpaper.primaryColors = null; if (DEBUG) { Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId + " name=" + name + " file=" + wallpaper.wallpaperFile.getName()); } return fd; } catch (FileNotFoundException e) { Slog.w(TAG, "Error setting wallpaper", e); } return null; }
/** * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped * for display. */ private void generateCrop(WallpaperData wallpaper) { boolean success = false; Rect cropHint = new Rect(wallpaper.cropHint); if (DEBUG) { Slog.v(TAG, "Generating crop for new wallpaper(s): 0x" + Integer.toHexString(wallpaper.whichPending) + " to " + wallpaper.cropFile.getName() + " crop=(" + cropHint.width() + 'x' + cropHint.height() + ") dim=(" + wallpaper.width + 'x' + wallpaper.height + ')'); } // Analyse the source; needed in multiple cases BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options); if (options.outWidth <= 0 || options.outHeight <= 0) { Slog.w(TAG, "Invalid wallpaper data"); success = false; } else { boolean needCrop = false; boolean needScale = false; // Empty crop means use the full image if (cropHint.isEmpty()) { cropHint.left = cropHint.top = 0; cropHint.right = options.outWidth; cropHint.bottom = options.outHeight; } else { // force the crop rect to lie within the measured bounds cropHint.offset( (cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0), (cropHint.bottom > options.outHeight ? options.outHeight - cropHint.bottom : 0)); // If the crop hint was larger than the image we just overshot. Patch things up. if (cropHint.left < 0) { cropHint.left = 0; } if (cropHint.top < 0) { cropHint.top = 0; } // Don't bother cropping if what we're left with is identity needCrop = (options.outHeight > cropHint.height() || options.outWidth > cropHint.width()); } // scale if the crop height winds up not matching the recommended metrics //needScale = (wallpaper.height != cropHint.height()); needScale = false; if (DEBUG) { Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height()); Slog.v(TAG, "dims: w=" + wallpaper.width + " h=" + wallpaper.height); Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight); Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale); } if (!needCrop && !needScale) { // Simple case: the nominal crop fits what we want, so we take // the whole thing and just copy the image file directly. if (DEBUG) { Slog.v(TAG, "Null crop of new wallpaper; copying"); } success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile); if (!success) { wallpaper.cropFile.delete(); // TODO: fall back to default wallpaper in this case } } else { // Fancy case: crop and scale. First, we decode and scale down if appropriate. FileOutputStream f = null; BufferedOutputStream bos = null; try { BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance( wallpaper.wallpaperFile.getAbsolutePath(), false); // This actually downsamples only by powers of two, but that's okay; we do // a proper scaling blit later. This is to minimize transient RAM use. // We calculate the largest power-of-two under the actual ratio rather than // just let the decode take care of it because we also want to remap where the // cropHint rectangle lies in the decoded [super]rect. final BitmapFactory.Options scaler; final int actualScale = cropHint.height() / wallpaper.height; int scale = 1; while (2*scale < actualScale) { scale *= 2; } if (scale > 1) { scaler = new BitmapFactory.Options(); scaler.inSampleSize = scale; if (DEBUG) { Slog.v(TAG, "Downsampling cropped rect with scale " + scale); } } else { scaler = null; } Bitmap cropped = decoder.decodeRegion(cropHint, scaler); decoder.recycle(); if (cropped == null) { Slog.e(TAG, "Could not decode new wallpaper"); } else { // We've got the extracted crop; now we want to scale it properly to // the desired rectangle. That's a height-biased operation: make it // fit the hinted height, and accept whatever width we end up with. cropHint.offsetTo(0, 0); cropHint.right /= scale; // adjust by downsampling factor cropHint.bottom /= scale; final float heightR = ((float)wallpaper.height) / ((float)cropHint.height()); if (DEBUG) { Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint); } final int destWidth = (int)(cropHint.width() * heightR); final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped, destWidth, wallpaper.height, true); if (DEBUG) { Slog.v(TAG, "Final extract:"); Slog.v(TAG, " dims: w=" + wallpaper.width + " h=" + wallpaper.height); Slog.v(TAG, " out: w=" + finalCrop.getWidth() + " h=" + finalCrop.getHeight()); } f = new FileOutputStream(wallpaper.cropFile); bos = new BufferedOutputStream(f, 32*1024); finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos); bos.flush(); // don't rely on the implicit flush-at-close when noting success success = true; } } catch (Exception e) { if (DEBUG) { Slog.e(TAG, "Error decoding crop", e); } } finally { IoUtils.closeQuietly(bos); IoUtils.closeQuietly(f); } } } if (!success) { Slog.e(TAG, "Unable to apply new wallpaper"); wallpaper.cropFile.delete(); } if (wallpaper.cropFile.exists()) { boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile()); if (DEBUG) { Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon); } } }