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);
}
}
}