标签:源码 android launcher wallpapercropactivit
最近两天改一个客户需求改得挺耗时,多数都用在了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
Android Launcher3源码分析(五)WallpaperCropActivity
标签:源码 android launcher wallpapercropactivit
原文地址:http://blog.csdn.net/zhoumushui/article/details/40897455