Android Launcher3源码分析(五)WallpaperCropActivity
最近两天改一个客户需求改得挺耗时,多数都用在了WallpaperCropActivity这个文件中。今天就顺带分析一下这个文件。
路径:packages/apps/Launcher3/src/com/android/launcher3/WallpaperCropActivity.java
这个Activity是Launcher设置壁纸的Activity,完成剪切壁纸大小,设置壁纸等操作。
就在代码里面加注释分析吧,方便一些。
因为我这边的代码是mediaTek定制过的,有些地方和Google官方不一样,所以就没用。以下代码是从网上找的Google官方的代码:
(其实前4篇都是mediaTek定制过的代码,当时也没有考虑到和Google的差异)
/* * Copyright (C) 2013 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.launcher3; import android.app.ActionBar; import android.app.Activity; import android.app.WallpaperManager; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.util.FloatMath; import android.util.Log; import android.view.Display; import android.view.View; import android.view.WindowManager; import com.android.gallery3d.common.Utils; import com.android.gallery3d.exif.ExifInterface; import com.android.photos.BitmapRegionTileSource; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; public class WallpaperCropActivity extends Activity { private static final String LOGTAG = "Launcher3.CropActivity"; protected static final String WALLPAPER_WIDTH_KEY = "wallpaper.width"; protected static final String WALLPAPER_HEIGHT_KEY = "wallpaper.height"; private static final int DEFAULT_COMPRESS_QUALITY = 90;<span style="white-space:pre"> </span>// 默认的图片压缩质量 /** * The maximum bitmap size we allow to be returned through the intent. * Intents have a maximum of 1MB in total size. However, the Bitmap seems to * have some overhead to hit so that we go way below the limit here to make * sure the intent stays below 1MB.We should consider just returning a byte * array instead of a Bitmap instance to avoid overhead. */ public static final int MAX_BMAP_IN_INTENT = 750000; private static final float WALLPAPER_SCREENS_SPAN = 2f; protected CropView mCropView; protected Uri mUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); init(); if (!enableRotation()) { setRequestedOrientation(Configuration.ORIENTATION_PORTRAIT); } } protected void init() { setContentView(R.layout.wallpaper_cropper); mCropView = (CropView) findViewById(R.id.cropView); Intent cropIntent = getIntent(); final Uri imageUri = cropIntent.getData(); if (imageUri == null) { Log.e(LOGTAG, "No URI passed in intent, exiting WallpaperCropActivity"); finish(); return; } int rotation = getRotationFromExif(this, imageUri); mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, rotation), null); mCropView.setTouchEnabled(true); // Action bar // Show the custom action bar view final ActionBar actionBar = getActionBar(); actionBar.setCustomView(R.layout.actionbar_set_wallpaper); actionBar.getCustomView().setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { boolean finishActivityWhenDone = true; cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone); } }); } public boolean enableRotation() { return getResources().getBoolean(R.bool.allow_rotation); } public static String getSharedPreferencesKey() { return WallpaperCropActivity.class.getName(); } // As a ratio of screen height, the total distance we want the parallax effect to span // horizontally private static float wallpaperTravelToScreenWidthRatio(int width, int height) { float aspectRatio = width / (float) height; // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width // We will use these two data points to extrapolate how much the wallpaper parallax effect // to span (ie travel) at any aspect ratio: final float ASPECT_RATIO_LANDSCAPE = 16/10f; final float ASPECT_RATIO_PORTRAIT = 10/16f; final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f; final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f; // To find out the desired width at different aspect ratios, we use the following two // formulas, where the coefficient on x is the aspect ratio (width/height): // (16/10)x + y = 1.5 // (10/16)x + y = 1.2 // We solve for x and y and end up with a final formula: final float x = (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) / (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT); final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT; return x * aspectRatio + y; }
/*<span style="white-space:pre"> </span>以下这个函数用来获取壁纸的长和宽,Google的源码逻辑还是要简单一些,没有做太多的定制。这个函数可以做很多扩展,比如说让横屏显示图片全部,让横屏和竖屏分别用两张分辨率不同长宽不同的图片等等。当然复杂了就容易有Bug,在锁屏界面进行转屏可能会出现闪屏的情况<span style="white-space:pre"> </span>*/ static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) { Point minDims = new Point(); Point maxDims = new Point(); windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims); int maxDim = Math.max(maxDims.x, maxDims.y); int minDim = Math.max(minDims.x, minDims.y); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { Point realSize = new Point(); windowManager.getDefaultDisplay().getRealSize(realSize); maxDim = Math.max(realSize.x, realSize.y); minDim = Math.min(realSize.x, realSize.y); } // We need to ensure that there is enough extra space in the wallpaper // for the intended // parallax effects final int defaultWidth, defaultHeight; if (isScreenLarge(res)) {<span style="white-space:pre"> </span>// 屏幕最短边大于720则被判定为大屏幕设备 defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim)); defaultHeight = maxDim; } else { defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim); defaultHeight = maxDim; } return new Point(defaultWidth, defaultHeight); } public static int getRotationFromExif(String path) { return getRotationFromExifHelper(path, null, 0, null, null); } public static int getRotationFromExif(Context context, Uri uri) { return getRotationFromExifHelper(null, null, 0, context, uri); } public static int getRotationFromExif(Resources res, int resId) { return getRotationFromExifHelper(null, res, resId, null, null); } private static int getRotationFromExifHelper( String path, Resources res, int resId, Context context, Uri uri) { ExifInterface ei = new ExifInterface(); try { if (path != null) { ei.readExif(path); } else if (uri != null) { InputStream is = context.getContentResolver().openInputStream(uri); BufferedInputStream bis = new BufferedInputStream(is); ei.readExif(bis); } else { InputStream is = res.openRawResource(resId); BufferedInputStream bis = new BufferedInputStream(is); ei.readExif(bis); } Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); if (ori != null) { return ExifInterface.getRotationForOrientationValue(ori.shortValue()); } } catch (IOException e) { Log.w(LOGTAG, "Getting exif data failed", e); } return 0; }
// 根据文件路径filePath设置壁纸 protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) { int rotation = getRotationFromExif(filePath); BitmapCropTask cropTask = new BitmapCropTask( this, filePath, null, rotation, 0, 0, true, false, null); final Point bounds = cropTask.getImageBounds(); Runnable onEndCrop = new Runnable() { public void run() { updateWallpaperDimensions(bounds.x, bounds.y); if (finishActivityWhenDone) { setResult(Activity.RESULT_OK); finish(); } } }; cropTask.setOnEndRunnable(onEndCrop); cropTask.setNoCrop(true); cropTask.execute(); }
/*这个函数无疑是剪切图片,然后设置壁纸了,图片的outSize由上面的函数getDefaultWallpaperSize所返回,这个函数也可以进行扩充,根据resId可以对默认壁纸和壁纸库里的其他壁纸进行区分,然后设置不同的响应函数,虽然我觉的这个在实际应用中的意义不大,但是永远不能低估客户的想象力和创造力,我还就偏偏遇到了这样的客户需求。*/ protected void cropImageAndSetWallpaper( Resources res, int resId, final boolean finishActivityWhenDone) { // crop this image and scale it down to the default wallpaper size for // this device int rotation = getRotationFromExif(res, resId); Point inSize = mCropView.getSourceDimensions(); Point outSize = getDefaultWallpaperSize(getResources(), getWindowManager()); RectF crop = getMaxCropRect( inSize.x, inSize.y, outSize.x, outSize.y, false); Runnable onEndCrop = new Runnable() { public void run() { // Passing 0, 0 will cause launcher to revert to using the // default wallpaper size updateWallpaperDimensions(0, 0); if (finishActivityWhenDone) { setResult(Activity.RESULT_OK); finish(); } } }; BitmapCropTask cropTask = new BitmapCropTask(this, res, resId, crop, rotation, outSize.x, outSize.y, true, false, onEndCrop); cropTask.execute(); }
/*这个函数就是上面说到的判断是否属于大屏幕设备的函数了,可以看到Google的定义是屏幕最短边大于720就算是了。自然可以根据自己的需要来修改这个数值*/ private static boolean isScreenLarge(Resources res) { Configuration config = res.getConfiguration(); return config.smallestScreenWidthDp >= 720; }
/*<pre name="code" class="java">不同参数的cropImageAndSetWallpaper,可以看到参数相比上面的cropImageAndSetWallpaper由resId变成了<pre name="code" class="java">OnBitmapCroppedHandler,处理过程相对复杂一些。而且加入了是否是LTR布局的判断。*/ protected void cropImageAndSetWallpaper(Uri uri, OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) { // Get the crop boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; Point minDims = new Point(); Point maxDims = new Point(); Display d = getWindowManager().getDefaultDisplay(); d.getCurrentSizeRange(minDims, maxDims); Point displaySize = new Point(); d.getSize(displaySize); int maxDim = Math.max(maxDims.x, maxDims.y); final int minDim = Math.min(minDims.x, minDims.y); int defaultWallpaperWidth; if (isScreenLarge(getResources())) { defaultWallpaperWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim)); } else { defaultWallpaperWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim); } boolean isPortrait = displaySize.x < displaySize.y; int portraitHeight; if (isPortrait) { portraitHeight = mCropView.getHeight(); } else { // TODO: how to actually get the proper portrait height? // This is not quite right: portraitHeight = Math.max(maxDims.x, maxDims.y); } if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { Point realSize = new Point(); d.getRealSize(realSize); portraitHeight = Math.max(realSize.x, realSize.y); } // Get the crop RectF cropRect = mCropView.getCrop(); int cropRotation = mCropView.getImageRotation(); float cropScale = mCropView.getWidth() / (float) cropRect.width(); Point inSize = mCropView.getSourceDimensions(); 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]); // 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 = defaultWallpaperWidth / 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 + portraitHeight / cropScale; } else { // LANDSCAPE float extraPortraitHeight = portraitHeight / 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); Runnable onEndCrop = new Runnable() { public void run() { updateWallpaperDimensions(outWidth, outHeight); if (finishActivityWhenDone) { setResult(Activity.RESULT_OK); finish(); } } }; BitmapCropTask cropTask = new BitmapCropTask(this, uri, cropRect, cropRotation, outWidth, outHeight, true, false, onEndCrop); if (onBitmapCroppedHandler != null) { cropTask.setOnBitmapCropped(onBitmapCroppedHandler); } cropTask.execute(); } public interface OnBitmapCroppedHandler { public void onBitmapCropped(byte[] imageBytes); }
/*这也是一个核心地方,完成裁剪工作。可以看出输出格式是jpg*/ protected static class BitmapCropTask extends AsyncTask<Void, Void, Boolean> { Uri mInUri = null; Context mContext; String mInFilePath; byte[] mInImageBytes; int mInResId = 0; InputStream mInStream; RectF mCropBounds = null; int mOutWidth, mOutHeight; int mRotation; String mOutputFormat = "jpg"; // for now boolean mSetWallpaper; boolean mSaveCroppedBitmap; Bitmap mCroppedBitmap; Runnable mOnEndRunnable; Resources mResources; OnBitmapCroppedHandler mOnBitmapCroppedHandler; boolean mNoCrop; public BitmapCropTask(Context c, String filePath, RectF cropBounds, int rotation, int outWidth, int outHeight, boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { mContext = c; mInFilePath = filePath; init(cropBounds, rotation, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); } public BitmapCropTask(byte[] imageBytes, RectF cropBounds, int rotation, int outWidth, int outHeight, boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { mInImageBytes = imageBytes; init(cropBounds, rotation, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); } public BitmapCropTask(Context c, Uri inUri, RectF cropBounds, int rotation, int outWidth, int outHeight, boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { mContext = c; mInUri = inUri; init(cropBounds, rotation, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); } public BitmapCropTask(Context c, Resources res, int inResId, RectF cropBounds, int rotation, int outWidth, int outHeight, boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { mContext = c; mInResId = inResId; mResources = res; init(cropBounds, rotation, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); } private void init(RectF cropBounds, int rotation, int outWidth, int outHeight, boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { mCropBounds = cropBounds; mRotation = rotation; mOutWidth = outWidth; mOutHeight = outHeight; mSetWallpaper = setWallpaper; mSaveCroppedBitmap = saveCroppedBitmap; mOnEndRunnable = onEndRunnable; } public void setOnBitmapCropped(OnBitmapCroppedHandler handler) { mOnBitmapCroppedHandler = handler; } public void setNoCrop(boolean value) { mNoCrop = value; } public void setOnEndRunnable(Runnable onEndRunnable) { mOnEndRunnable = onEndRunnable; } // Helper to setup input stream private void regenerateInputStream() { if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) { Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " + "image byte array given"); } else { Utils.closeSilently(mInStream); try { if (mInUri != null) { mInStream = new BufferedInputStream( mContext.getContentResolver().openInputStream(mInUri)); } else if (mInFilePath != null) { mInStream = mContext.openFileInput(mInFilePath); } else if (mInImageBytes != null) { mInStream = new BufferedInputStream( new ByteArrayInputStream(mInImageBytes)); } else { mInStream = new BufferedInputStream( mResources.openRawResource(mInResId)); } } catch (FileNotFoundException e) { Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e); } } } public Point getImageBounds() { regenerateInputStream();<span style="white-space:pre"> </span>// 重新生成输入流 if (mInStream != null) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(mInStream, null, options); if (options.outWidth != 0 && options.outHeight != 0) { return new Point(options.outWidth, options.outHeight); } } return null; } public void setCropBounds(RectF cropBounds) { mCropBounds = cropBounds; } public Bitmap getCroppedBitmap() { return mCroppedBitmap; } public boolean cropBitmap() { boolean failure = false; regenerateInputStream(); WallpaperManager wallpaperManager = null; if (mSetWallpaper) { wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext()); } if (mSetWallpaper && mNoCrop && mInStream != null) { try { wallpaperManager.setStream(mInStream); } catch (IOException e) { Log.w(LOGTAG, "cannot write stream to wallpaper", e); failure = true; } return !failure; } if (mInStream != null) { // Find crop bounds (scaled to original image size) Rect roundedTrueCrop = new Rect(); Matrix rotateMatrix = new Matrix(); Matrix inverseRotateMatrix = new Matrix(); if (mRotation > 0) { rotateMatrix.setRotate(mRotation); inverseRotateMatrix.setRotate(-mRotation); mCropBounds.roundOut(roundedTrueCrop); mCropBounds = new RectF(roundedTrueCrop); Point bounds = getImageBounds(); float[] rotatedBounds = new float[] { bounds.x, bounds.y }; rotateMatrix.mapPoints(rotatedBounds); rotatedBounds[0] = Math.abs(rotatedBounds[0]); rotatedBounds[1] = Math.abs(rotatedBounds[1]); mCropBounds.offset(-rotatedBounds[0]/2, -rotatedBounds[1]/2); inverseRotateMatrix.mapRect(mCropBounds); mCropBounds.offset(bounds.x/2, bounds.y/2); regenerateInputStream(); } mCropBounds.roundOut(roundedTrueCrop); if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) { Log.w(LOGTAG, "crop has bad values for full size image"); failure = true; return false; } // See how much we're reducing the size of the image int scaleDownSampleSize = Math.min(roundedTrueCrop.width() / mOutWidth, roundedTrueCrop.height() / mOutHeight); // Attempt to open a region decoder BitmapRegionDecoder decoder = null; try { decoder = BitmapRegionDecoder.newInstance(mInStream, true); } catch (IOException e) { Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e); } Bitmap crop = null; if (decoder != null) { // Do region decoding to get crop bitmap BitmapFactory.Options options = new BitmapFactory.Options(); if (scaleDownSampleSize > 1) { options.inSampleSize = scaleDownSampleSize; } crop = decoder.decodeRegion(roundedTrueCrop, options); decoder.recycle(); } if (crop == null) { // BitmapRegionDecoder has failed, try to crop in-memory regenerateInputStream(); Bitmap fullSize = null; if (mInStream != null) { BitmapFactory.Options options = new BitmapFactory.Options(); if (scaleDownSampleSize > 1) { options.inSampleSize = scaleDownSampleSize; } fullSize = BitmapFactory.decodeStream(mInStream, null, options); } if (fullSize != null) { mCropBounds.left /= scaleDownSampleSize; mCropBounds.top /= scaleDownSampleSize; mCropBounds.bottom /= scaleDownSampleSize; mCropBounds.right /= scaleDownSampleSize; mCropBounds.roundOut(roundedTrueCrop); crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left, roundedTrueCrop.top, roundedTrueCrop.width(), roundedTrueCrop.height()); } } if (crop == null) { Log.w(LOGTAG, "cannot decode file: " + mInUri.toString()); failure = true; return false; } if (mOutWidth > 0 && mOutHeight > 0 || mRotation > 0) { float[] dimsAfter = new float[] { crop.getWidth(), crop.getHeight() }; rotateMatrix.mapPoints(dimsAfter); dimsAfter[0] = Math.abs(dimsAfter[0]); dimsAfter[1] = Math.abs(dimsAfter[1]); if (!(mOutWidth > 0 && mOutHeight > 0)) { mOutWidth = Math.round(dimsAfter[0]); mOutHeight = Math.round(dimsAfter[1]); } RectF cropRect = new RectF(0, 0, dimsAfter[0], dimsAfter[1]); RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight); Matrix m = new Matrix(); if (mRotation == 0) { m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL); } else { Matrix m1 = new Matrix(); m1.setTranslate(-crop.getWidth() / 2f, -crop.getHeight() / 2f); Matrix m2 = new Matrix(); m2.setRotate(mRotation); Matrix m3 = new Matrix(); m3.setTranslate(dimsAfter[0] / 2f, dimsAfter[1] / 2f); Matrix m4 = new Matrix(); m4.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL); Matrix c1 = new Matrix(); c1.setConcat(m2, m1); Matrix c2 = new Matrix(); c2.setConcat(m4, m3); m.setConcat(c2, c1); } Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(), (int) returnRect.height(), Bitmap.Config.ARGB_8888); if (tmp != null) { Canvas c = new Canvas(tmp); Paint p = new Paint(); p.setFilterBitmap(true); c.drawBitmap(crop, m, p); crop = tmp; } } if (mSaveCroppedBitmap) { mCroppedBitmap = crop; } // Get output compression format CompressFormat cf = convertExtensionToCompressFormat(getFileExtension(mOutputFormat)); // Compress to byte array ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048); if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) { // If we need to set to the wallpaper, set it if (mSetWallpaper && wallpaperManager != null) { try { byte[] outByteArray = tmpOut.toByteArray(); wallpaperManager.setStream(new ByteArrayInputStream(outByteArray)); if (mOnBitmapCroppedHandler != null) { mOnBitmapCroppedHandler.onBitmapCropped(outByteArray); } } catch (IOException e) { Log.w(LOGTAG, "cannot write stream to wallpaper", e); failure = true; } } } else { Log.w(LOGTAG, "cannot compress bitmap"); failure = true; } } return !failure; // True if any of the operations failed } @Override protected Boolean doInBackground(Void... params) { return cropBitmap(); } @Override protected void onPostExecute(Boolean result) { if (mOnEndRunnable != null) { mOnEndRunnable.run(); } } } protected void updateWallpaperDimensions(int width, int height) { String spKey = getSharedPreferencesKey(); SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); if (width != 0 && height != 0) { editor.putInt(WALLPAPER_WIDTH_KEY, width); editor.putInt(WALLPAPER_HEIGHT_KEY, height); } else { editor.remove(WALLPAPER_WIDTH_KEY); editor.remove(WALLPAPER_HEIGHT_KEY); } editor.commit(); suggestWallpaperDimension(getResources(), sp, getWindowManager(), WallpaperManager.getInstance(this)); } static public void suggestWallpaperDimension(Resources res, final SharedPreferences sharedPrefs, WindowManager windowManager, final WallpaperManager wallpaperManager) { final Point defaultWallpaperSize = getDefaultWallpaperSize(res, windowManager); new Thread("suggestWallpaperDimension") { public void run() { // If we have saved a wallpaper width/height, use that instead int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, defaultWallpaperSize.x); int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, defaultWallpaperSize.y); wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight); } }.start(); } protected static RectF getMaxCropRect( int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) { RectF cropRect = new RectF(); // Get a crop rect that will fit this if (inWidth / (float) inHeight > outWidth / (float) outHeight) { cropRect.top = 0; cropRect.bottom = inHeight; cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2; cropRect.right = inWidth - cropRect.left; if (leftAligned) { cropRect.right -= cropRect.left; cropRect.left = 0; } } else { cropRect.left = 0; cropRect.right = inWidth; cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2; cropRect.bottom = inHeight - cropRect.top; } return cropRect; } protected static CompressFormat convertExtensionToCompressFormat(String extension) { return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG; } protected static String getFileExtension(String requestFormat) { String outputFormat = (requestFormat == null) ? "jpg" : requestFormat; outputFormat = outputFormat.toLowerCase(); return (outputFormat.equals("png") || outputFormat.equals("gif")) ? "png" // We don't support gif compression. : "jpg"; } }
核心的部分也不是很多,其他不少地方都已经用英文标注了,相信看这篇文字的都是IT人,英语自然不在话下,就不充当翻译了。
转载请注明出处:周木水的CSDN博客 http://blog.csdn.net/zhoumushui
我的GitHub:周木水的GitHub https://github.com/zhoumushui
文章来自:http://blog.csdn.net/zhoumushui/article/details/40897455