如果是KitKat以下版本,那么会调用以下方法:

int width = getWallpaperDesiredMinimumWidth();

int height = getWallpaperDesiredMinimumHeight();

Point size = getDefaultDisplaySize( new Point());

float spotlightX = (float) size.x / width;

float spotlightY = (float) size.y / height;

cropAndSetWallpaperIntent = new Intent(CropActivity.CROP_ACTION )

.setClass( this, CropActivity.class)

.setDataAndType( mPickedItem, IMAGE_TYPE)

.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT )

.putExtra(CropExtras. KEY_OUTPUT_X, width)

.putExtra(CropExtras. KEY_OUTPUT_Y, height)

.putExtra(CropExtras. KEY_ASPECT_X, width)

.putExtra(CropExtras. KEY_ASPECT_Y, height)

.putExtra(CropExtras. KEY_SPOTLIGHT_X, spotlightX)

.putExtra(CropExtras. KEY_SPOTLIGHT_Y, spotlightY)

.putExtra(CropExtras. KEY_SCALE, true )

.putExtra(CropExtras.KEY_SCALE_UP_IF_NEEDED , true)

.putExtra(CropExtras.KEY_SET_AS_WALLPAPER , true);

startActivity(cropAndSetWallpaperIntent);

finish();

先是调用系统方法获取期望的壁纸的最小宽度和最小高度。然后是CropExtras这个类,这个实体类描述了剪裁壁纸的信息,包括长宽、缩放、格式等等。代码如下:/*

* Copyright (C) 2012 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.gallery3d.filtershow.crop;

import android.net.Uri;

public class CropExtras {

public static final String KEY_CROPPED_RECT = "cropped-rect";

public static final String KEY_OUTPUT_X = "outputX";

public static final String KEY_OUTPUT_Y = "outputY";

public static final String KEY_SCALE = "scale";

public static final String KEY_SCALE_UP_IF_NEEDED = "scaleUpIfNeeded";

public static final String KEY_ASPECT_X = "aspectX";

public static final String KEY_ASPECT_Y = "aspectY";

public static final String KEY_SET_AS_WALLPAPER = "set-as-wallpaper";

public static final String KEY_RETURN_DATA = "return-data";

public static final String KEY_DATA = "data";

public static final String KEY_SPOTLIGHT_X = "spotlightX";

public static final String KEY_SPOTLIGHT_Y = "spotlightY";

public static final String KEY_SHOW_WHEN_LOCKED = "showWhenLocked";

public static final String KEY_OUTPUT_FORMAT = "outputFormat";

private int mOutputX = 0;

private int mOutputY = 0;

private boolean mScaleUp = true;

private int mAspectX = 0;

private int mAspectY = 0;

private boolean mSetAsWallpaper = false;

private boolean mReturnData = false;

private Uri mExtraOutput = null;

private String mOutputFormat = null;

private boolean mShowWhenLocked = false;

private float mSpotlightX = 0;

private float mSpotlightY = 0;

public CropExtras(int outputX, int outputY, boolean scaleUp, int aspectX, int aspectY,

boolean setAsWallpaper, boolean returnData, Uri extraOutput, String outputFormat,

boolean showWhenLocked, float spotlightX, float spotlightY) {

mOutputX = outputX;

mOutputY = outputY;

mScaleUp = scaleUp;

mAspectX = aspectX;

mAspectY = aspectY;

mSetAsWallpaper = setAsWallpaper;

mReturnData = returnData;

mExtraOutput = extraOutput;

mOutputFormat = outputFormat;

mShowWhenLocked = showWhenLocked;

mSpotlightX = spotlightX;

mSpotlightY = spotlightY;

}

public CropExtras(CropExtras c) {

this(c.mOutputX, c.mOutputY, c.mScaleUp, c.mAspectX, c.mAspectY, c.mSetAsWallpaper,

c.mReturnData, c.mExtraOutput, c.mOutputFormat, c.mShowWhenLocked,

c.mSpotlightX, c.mSpotlightY);

}

public int getOutputX() {

return mOutputX;

}

public int getOutputY() {

return mOutputY;

}

public boolean getScaleUp() {

return mScaleUp;

}

public int getAspectX() {

return mAspectX;

}

public int getAspectY() {

return mAspectY;

}

public boolean getSetAsWallpaper() {

return mSetAsWallpaper;

}

public boolean getReturnData() {

return mReturnData;

}

public Uri getExtraOutput() {

return mExtraOutput;

}

public String getOutputFormat() {

return mOutputFormat;

}

public boolean getShowWhenLocked() {

return mShowWhenLocked;

}

public float getSpotlightX() {

return mSpotlightX;

}

public float getSpotlightY() {

return mSpotlightY;

}

}

不过对于类成员属性我们并不清楚各自代表什么意思,不过从传递进去的参数来看,是可以发现一些端倪的。比如KEY_OUTPUT_X现在可以简单的理解为width,同理高度也一样。进入CropActivity的时候会把这些信息传递过去。CropActivity就是上面那个可以缩放设置壁纸的界面,完成这个功能的那个其实是一个自定义View:CropView。接着来到CropActivity,这就是图-3所显示的Activity。这个类所在包以及其他类如下:

图-6

可以看到共有七个类一起完成壁纸移动、缩放设置的功能,当然最核心的是CropActivity,它负责统筹调度其他类。代码如下:/*

* 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.gallery3d.filtershow.crop;

import android.app.ActionBar;

import android.app.Activity;

import android.app.WallpaperManager;

import android.content.Context;

import android.content.Intent;

import android.content.res.Configuration;

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.Rect;

import android.graphics.RectF;

import android.net.Uri;

import android.os.AsyncTask;

import android.os.Bundle;

import android.provider.MediaStore;

import android.util.DisplayMetrics;

import android.util.Log;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.WindowManager;

import android.widget.Toast;

import com.android.gallery3d.R;

import com.android.gallery3d.common.Utils;

import com.android.gallery3d.filtershow.cache.ImageLoader;

import com.android.gallery3d.filtershow.tools.SaveImage;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

/**

* Activity for cropping an image.

*/

public class CropActivity extends Activity {

private static final String LOGTAG = "CropActivity";

public static final String CROP_ACTION = "com.android.camera.action.CROP";

// 剪裁信息

private CropExtras mCropExtras = null;

// 加载Bitmap

private LoadBitmapTask mLoadBitmapTask = null;

private int mOutputX = 0;

private int mOutputY = 0;

private Bitmap mOriginalBitmap = null;

private RectF mOriginalBounds = null;

private int mOriginalRotation = 0;

private Uri mSourceUri = null;

// 自定义的View 剪裁壁纸

private CropView mCropView = null;

// 保存的button

private View mSaveButton = null;

// 保护IO操作

private boolean finalIOGuard = false;

private static final int SELECT_PICTURE = 1; // request code for picker

private static final int DEFAULT_COMPRESS_QUALITY = 90;

/**

* 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;

// Flags

private static final int DO_SET_WALLPAPER = 1;

private static final int DO_RETURN_DATA = 1 << 1;

private static final int DO_EXTRA_OUTPUT = 1 << 2;

private static final int FLAG_CHECK = DO_SET_WALLPAPER | DO_RETURN_DATA | DO_EXTRA_OUTPUT;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

//

Intent intent = getIntent();

setResult(RESULT_CANCELED, new Intent());

mCropExtras = getExtrasFromIntent(intent);

//

if (mCropExtras != null && mCropExtras.getShowWhenLocked()) {

getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);

}

setContentView(R.layout.crop_activity);

mCropView = (CropView) findViewById(R.id.cropView);

// 自定义ActionBar布局 添加的Button用于保存设置壁纸

ActionBar actionBar = getActionBar();

if (actionBar != null) {

actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);

actionBar.setCustomView(R.layout.filtershow_actionbar);

View mSaveButton = actionBar.getCustomView();

mSaveButton.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View view) {

// 保存设置剪裁的壁纸

startFinishOutput();

}

});

}

if (intent.getData() != null) {

mSourceUri = intent.getData();

// 开始加载之前选择的图片

startLoadBitmap(mSourceUri);

} else {

// 否则回去选图片

pickImage();

}

}

private void enableSave(boolean enable) {

if (mSaveButton != null) {

mSaveButton.setEnabled(enable);

}

}

@Override

protected void onDestroy() {

// 取消加载Bitmap的任务

if (mLoadBitmapTask != null) {

mLoadBitmapTask.cancel(false);

}

super.onDestroy();

}

@Override

public void onConfigurationChanged (Configuration newConfig) {

super.onConfigurationChanged(newConfig);

mCropView.configChanged();

}

/**

* Opens a selector in Gallery to chose an image for use when none was given

* in the CROP intent.

*/

private void pickImage() {

Intent intent = new Intent();

intent.setType("image/*");

intent.setAction(Intent.ACTION_GET_CONTENT);

startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)),

SELECT_PICTURE);

}

/**

* Callback for pickImage().

*/

@Override

public void onActivityResult(int requestCode, int resultCode, Intent data) {

if (resultCode == RESULT_OK && requestCode == SELECT_PICTURE) {

mSourceUri = data.getData();

startLoadBitmap(mSourceUri);

}

}

/**

* Gets screen size metric.

* 通过获取屏幕的宽和高 返回二者中的最大值 一般的竖屏手机肯定是返回高度了

*/

private int getScreenImageSize() {

DisplayMetrics outMetrics = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(outMetrics);

return (int) Math.max(outMetrics.heightPixels, outMetrics.widthPixels);

}

/**

* Method that loads a bitmap in an async task.

* 启动一个一步任务去加载Bitmap 这个Bitmap就是之前我们选择要设置为壁纸的图片

*/

private void startLoadBitmap(Uri uri) {

if (uri != null) {

enableSave(false);

final View loading = findViewById(R.id.loading);

loading.setVisibility(View.VISIBLE);

mLoadBitmapTask = new LoadBitmapTask();

mLoadBitmapTask.execute(uri);

} else {

cannotLoadImage();

done();

}

}

/**

* Method called on UI thread with loaded bitmap.

* 当加载完Bitmap之后将Bitmap赋值给mCropView 接着它负责图像的剪裁工作

*/

private void doneLoadBitmap(Bitmap bitmap, RectF bounds, int orientation) {

final View loading = findViewById(R.id.loading);

loading.setVisibility(View.GONE);

mOriginalBitmap = bitmap;

mOriginalBounds = bounds;

mOriginalRotation = orientation;

if (bitmap != null && bitmap.getWidth() != 0 && bitmap.getHeight() != 0) {

RectF imgBounds = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());

mCropView.initialize(bitmap, imgBounds, imgBounds, orientation);

if (mCropExtras != null) {

int aspectX = mCropExtras.getAspectX();

int aspectY = mCropExtras.getAspectY();

mOutputX = mCropExtras.getOutputX();

mOutputY = mCropExtras.getOutputY();

if (mOutputX > 0 && mOutputY > 0) {

mCropView.applyAspect(mOutputX, mOutputY);

}

float spotX = mCropExtras.getSpotlightX();

float spotY = mCropExtras.getSpotlightY();

if (spotX > 0 && spotY > 0) {

mCropView.setWallpaperSpotlight(spotX, spotY);

}

if (aspectX > 0 && aspectY > 0) {

mCropView.applyAspect(aspectX, aspectY);

}

}

enableSave(true);

} else {

Log.w(LOGTAG, "could not load image for cropping");

cannotLoadImage();

setResult(RESULT_CANCELED, new Intent());

done();

}

}

/**

* Display toast for image loading failure.

* 无法加载图片

*/

private void cannotLoadImage() {

CharSequence text = getString(R.string.cannot_load_image);

Toast toast = Toast.makeText(this, text, Toast.LENGTH_SHORT);

toast.show();

}

/**

* AsyncTask for loading a bitmap into memory.

* 异步任务加载bitmap到内存

* @see #startLoadBitmap(Uri)

* @see #doneLoadBitmap(Bitmap)

*/

private class LoadBitmapTask extends AsyncTask {

int mBitmapSize;

Context mContext;

Rect mOriginalBounds;

int mOrientation;

public LoadBitmapTask() {

mBitmapSize = getScreenImageSize();

mContext = getApplicationContext();

mOriginalBounds = new Rect();

mOrientation = 0;

}

@Override

protected Bitmap doInBackground(Uri... params) {

Uri uri = params[0];

Bitmap bmap = ImageLoader.loadConstrainedBitmap(uri, mContext, mBitmapSize,

mOriginalBounds, false);

mOrientation = ImageLoader.getMetadataRotation(mContext, uri);

return bmap;

}

@Override

protected void onPostExecute(Bitmap result) {

doneLoadBitmap(result, new RectF(mOriginalBounds), mOrientation);

}

}

/**

*

*/

protected void startFinishOutput() {

if (finalIOGuard) {

return;

} else {

finalIOGuard = true;

}

enableSave(false);

Uri destinationUri = null;

int flags = 0;

if (mOriginalBitmap != null && mCropExtras != null) {

if (mCropExtras.getExtraOutput() != null) {

destinationUri = mCropExtras.getExtraOutput();

if (destinationUri != null) {

flags |= DO_EXTRA_OUTPUT;

}

}

if (mCropExtras.getSetAsWallpaper()) {

flags |= DO_SET_WALLPAPER;

}

if (mCropExtras.getReturnData()) {

flags |= DO_RETURN_DATA;

}

}

if (flags == 0) {

destinationUri = SaveImage.makeAndInsertUri(this, mSourceUri);

if (destinationUri != null) {

flags |= DO_EXTRA_OUTPUT;

}

}

if ((flags & FLAG_CHECK) != 0 && mOriginalBitmap != null) {

RectF photo = new RectF(0, 0, mOriginalBitmap.getWidth(), mOriginalBitmap.getHeight());

RectF crop = getBitmapCrop(photo);

startBitmapIO(flags, mOriginalBitmap, mSourceUri, destinationUri, crop,

photo, mOriginalBounds,

(mCropExtras == null) ? null : mCropExtras.getOutputFormat(), mOriginalRotation);

return;

}

setResult(RESULT_CANCELED, new Intent());

done();

return;

}

/**

* @category 开始BitmapIOTask任务

* @param flags

* @param currentBitmap

* @param sourceUri

* @param destUri

* @param cropBounds

* @param photoBounds

* @param currentBitmapBounds

* @param format

* @param rotation

*/

private void startBitmapIO(int flags, Bitmap currentBitmap, Uri sourceUri, Uri destUri,

RectF cropBounds, RectF photoBounds, RectF currentBitmapBounds, String format,

int rotation) {

if (cropBounds == null || photoBounds == null || currentBitmap == null

|| currentBitmap.getWidth() == 0 || currentBitmap.getHeight() == 0

|| cropBounds.width() == 0 || cropBounds.height() == 0 || photoBounds.width() == 0

|| photoBounds.height() == 0) {

return; // fail fast

}

if ((flags & FLAG_CHECK) == 0) {

return; // no output options

}

if ((flags & DO_SET_WALLPAPER) != 0) {

Toast.makeText(this, R.string.setting_wallpaper, Toast.LENGTH_LONG).show();

}

final View loading = findViewById(R.id.loading);

loading.setVisibility(View.VISIBLE);

BitmapIOTask ioTask = new BitmapIOTask(sourceUri, destUri, format, flags, cropBounds,

photoBounds, currentBitmapBounds, rotation, mOutputX, mOutputY);

ioTask.execute(currentBitmap);

}

/**

* 完成BitmapIO任务

*/

private void doneBitmapIO(boolean success, Intent intent) {

final View loading = findViewById(R.id.loading);

loading.setVisibility(View.GONE);

if (success) {

setResult(RESULT_OK, intent);

} else {

setResult(RESULT_CANCELED, intent);

}

done();

}

/**

* 对传递进来的Bimap进行处理,然后设置成壁纸

*/

private class BitmapIOTask extends AsyncTask {

private final WallpaperManager mWPManager;

InputStream mInStream = null;

OutputStream mOutStream = null;

String mOutputFormat = null;

Uri mOutUri = null;

Uri mInUri = null;

int mFlags = 0;

RectF mCrop = null;

RectF mPhoto = null;

RectF mOrig = null;

Intent mResultIntent = null;

int mRotation = 0;

// Helper to setup input stream

private void regenerateInputStream() {

if (mInUri == null) {

Log.w(LOGTAG, "cannot read original file, no input URI given");

} else {

Utils.closeSilently(mInStream);

try {

mInStream = getContentResolver().openInputStream(mInUri);

} catch (FileNotFoundException e) {

Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e);

}

}

}

public BitmapIOTask(Uri sourceUri, Uri destUri, String outputFormat, int flags,

RectF cropBounds, RectF photoBounds, RectF originalBitmapBounds, int rotation,

int outputX, int outputY) {

mOutputFormat = outputFormat;

mOutStream = null;

mOutUri = destUri;

mInUri = sourceUri;

mFlags = flags;

mCrop = cropBounds;

mPhoto = photoBounds;

mOrig = originalBitmapBounds;

mWPManager = WallpaperManager.getInstance(getApplicationContext());

mResultIntent = new Intent();

mRotation = (rotation < 0) ? -rotation : rotation;

mRotation %= 360;

mRotation = 90 * (int) (mRotation / 90); // now mRotation is a multiple of 90

mOutputX = outputX;

mOutputY = outputY;

if ((flags & DO_EXTRA_OUTPUT) != 0) {

if (mOutUri == null) {

Log.w(LOGTAG, "cannot write file, no output URI given");

} else {

try {

mOutStream = getContentResolver().openOutputStream(mOutUri);

} catch (FileNotFoundException e) {

Log.w(LOGTAG, "cannot write file: " + mOutUri.toString(), e);

}

}

}

if ((flags & (DO_EXTRA_OUTPUT | DO_SET_WALLPAPER)) != 0) {

regenerateInputStream();

}

}

@Override

protected Boolean doInBackground(Bitmap... params) {

boolean failure = false;

Bitmap img = params[0];

// Set extra for crop bounds

if (mCrop != null && mPhoto != null && mOrig != null) {

RectF trueCrop = CropMath.getScaledCropBounds(mCrop, mPhoto, mOrig);

Matrix m = new Matrix();

m.setRotate(mRotation);

m.mapRect(trueCrop);

if (trueCrop != null) {

Rect rounded = new Rect();

trueCrop.roundOut(rounded);

mResultIntent.putExtra(CropExtras.KEY_CROPPED_RECT, rounded);

}

}

// Find the small cropped bitmap that is returned in the intent

if ((mFlags & DO_RETURN_DATA) != 0) {

assert (img != null);

Bitmap ret = getCroppedImage(img, mCrop, mPhoto);

if (ret != null) {

ret = getDownsampledBitmap(ret, MAX_BMAP_IN_INTENT);

}

if (ret == null) {

Log.w(LOGTAG, "could not downsample bitmap to return in data");

failure = true;

} else {

if (mRotation > 0) {

Matrix m = new Matrix();

m.setRotate(mRotation);

Bitmap tmp = Bitmap.createBitmap(ret, 0, 0, ret.getWidth(),

ret.getHeight(), m, true);

if (tmp != null) {

ret = tmp;

}

}

mResultIntent.putExtra(CropExtras.KEY_DATA, ret);

}

}

// Do the large cropped bitmap and/or set the wallpaper

if ((mFlags & (DO_EXTRA_OUTPUT | DO_SET_WALLPAPER)) != 0 && mInStream != null) {

// Find crop bounds (scaled to original image size)

RectF trueCrop = CropMath.getScaledCropBounds(mCrop, mPhoto, mOrig);

if (trueCrop == null) {

Log.w(LOGTAG, "cannot find crop for full size image");

failure = true;

return false;

}

Rect roundedTrueCrop = new Rect();

trueCrop.roundOut(roundedTrueCrop);

if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {

Log.w(LOGTAG, "crop has bad values for full size image");

failure = true;

return false;

}

// 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();

options.inMutable = true;

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) {

fullSize = BitmapFactory.decodeStream(mInStream);

}

if (fullSize != null) {

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 (mOutputX > 0 && mOutputY > 0) {

Matrix m = new Matrix();

RectF cropRect = new RectF(0, 0, crop.getWidth(), crop.getHeight());

if (mRotation > 0) {

m.setRotate(mRotation);

m.mapRect(cropRect);

}

RectF returnRect = new RectF(0, 0, mOutputX, mOutputY);

m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);

m.preRotate(mRotation);

Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),

(int) returnRect.height(), Bitmap.Config.ARGB_8888);

if (tmp != null) {

Canvas c = new Canvas(tmp);

c.drawBitmap(crop, m, new Paint());

crop = tmp;

}

} else if (mRotation > 0) {

Matrix m = new Matrix();

m.setRotate(mRotation);

Bitmap tmp = Bitmap.createBitmap(crop, 0, 0, crop.getWidth(),

crop.getHeight(), m, true);

if (tmp != null) {

crop = tmp;

}

}

// Get output compression format

CompressFormat cf =

convertExtensionToCompressFormat(getFileExtension(mOutputFormat));

// If we only need to output to a URI, compress straight to file

if (mFlags == DO_EXTRA_OUTPUT) {

if (mOutStream == null

|| !crop.compress(cf, DEFAULT_COMPRESS_QUALITY, mOutStream)) {

Log.w(LOGTAG, "failed to compress bitmap to file: " + mOutUri.toString());

failure = true;

} else {

mResultIntent.setData(mOutUri);

}

} else {

// Compress to byte array

ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);

if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) {

// If we need to output to a Uri, write compressed

// bitmap out

if ((mFlags & DO_EXTRA_OUTPUT) != 0) {

if (mOutStream == null) {

Log.w(LOGTAG,

"failed to compress bitmap to file: " + mOutUri.toString());

failure = true;

} else {

try {

mOutStream.write(tmpOut.toByteArray());

mResultIntent.setData(mOutUri);

} catch (IOException e) {

Log.w(LOGTAG,

"failed to compress bitmap to file: "

+ mOutUri.toString(), e);

failure = true;

}

}

}

// If we need to set to the wallpaper, set it

if ((mFlags & DO_SET_WALLPAPER) != 0 && mWPManager != null) {

if (mWPManager == null) {

Log.w(LOGTAG, "no wallpaper manager");

failure = true;

} else {

try {

mWPManager.setStream(new ByteArrayInputStream(tmpOut

.toByteArray()));

} 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 void onPostExecute(Boolean result) {

Utils.closeSilently(mOutStream);

Utils.closeSilently(mInStream);

doneBitmapIO(result.booleanValue(), mResultIntent);

}

}

private void done() {

finish();

}

/**

* @category 返回CroppedImage

* @param image

* @param cropBounds

* @param photoBounds

* @return

*/

protected static Bitmap getCroppedImage(Bitmap image, RectF cropBounds, RectF photoBounds) {

RectF imageBounds = new RectF(0, 0, image.getWidth(), image.getHeight());

RectF crop = CropMath.getScaledCropBounds(cropBounds, photoBounds, imageBounds);

if (crop == null) {

return null;

}

Rect intCrop = new Rect();

crop.roundOut(intCrop);

return Bitmap.createBitmap(image, intCrop.left, intCrop.top, intCrop.width(),

intCrop.height());

}

protected static Bitmap getDownsampledBitmap(Bitmap image, int max_size) {

if (image == null || image.getWidth() == 0 || image.getHeight() == 0 || max_size < 16) {

throw new IllegalArgumentException("Bad argument to getDownsampledBitmap()");

}

int shifts = 0;

int size = CropMath.getBitmapSize(image);

while (size > max_size) {

shifts++;

size /= 4;

}

Bitmap ret = Bitmap.createScaledBitmap(image, image.getWidth() >> shifts,

image.getHeight() >> shifts, true);

if (ret == null) {

return null;

}

// Handle edge case for rounding.

if (CropMath.getBitmapSize(ret) > max_size) {

return Bitmap.createScaledBitmap(ret, ret.getWidth() >> 1, ret.getHeight() >> 1, true);

}

return ret;

}

/**

* Gets the crop extras from the intent, or null if none exist.

*/

protected static CropExtras getExtrasFromIntent(Intent intent) {

Bundle extras = intent.getExtras();

if (extras != null) {

return new CropExtras(extras.getInt(CropExtras.KEY_OUTPUT_X, 0),

extras.getInt(CropExtras.KEY_OUTPUT_Y, 0),

extras.getBoolean(CropExtras.KEY_SCALE, true) &&

extras.getBoolean(CropExtras.KEY_SCALE_UP_IF_NEEDED, false),

extras.getInt(CropExtras.KEY_ASPECT_X, 0),

extras.getInt(CropExtras.KEY_ASPECT_Y, 0),

extras.getBoolean(CropExtras.KEY_SET_AS_WALLPAPER, false),

extras.getBoolean(CropExtras.KEY_RETURN_DATA, false),

(Uri) extras.getParcelable(MediaStore.EXTRA_OUTPUT),

extras.getString(CropExtras.KEY_OUTPUT_FORMAT),

extras.getBoolean(CropExtras.KEY_SHOW_WHEN_LOCKED, false),

extras.getFloat(CropExtras.KEY_SPOTLIGHT_X),

extras.getFloat(CropExtras.KEY_SPOTLIGHT_Y));

}

return null;

}

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";

}

private RectF getBitmapCrop(RectF imageBounds) {

RectF crop = mCropView.getCrop();

RectF photo = mCropView.getPhoto();

if (crop == null || photo == null) {

Log.w(LOGTAG, "could not get crop");

return null;

}

RectF scaledCrop = CropMath.getScaledCropBounds(crop, photo, imageBounds);

return scaledCrop;

}

}

CropActivity的处理逻辑是这样,首先开启一个异步任务根据传递过来的信息去加载壁纸Bitmap。加载完毕再开启一个异步任务去处理这个Bitmap,处理完最后设置为壁纸。代码已经添加了注释。

设置完毕返回到桌面,会有1到2秒的设置时间,之后壁纸就设置好了。设置好的壁纸是可以随着桌面滑动的,这么说不太准确,应该说是Launcher让壁纸随着桌面滑动而滑动(parallax effects)。处理逻辑是在Workspace类里,由于Workspace类代码较长就不贴代码了,找相关代码分析。

变量:private float mWallpaperScrollRatio = 1.0f;

private int mOriginalPageSpacing ;

private final WallpaperManager mWallpaperManager;

private IBinder mWindowToken;

private static final float WALLPAPER_SCREENS_SPAN = 2f;

enum WallpaperVerticalOffset {

TOP, MIDDLE , BOTTOM

};

int mWallpaperWidth;

int mWallpaperHeight;

WallpaperOffsetInterpolator mWallpaperOffset;

boolean mUpdateWallpaperOffsetImmediately = false ;

private Runnable mDelayedResizeRunnable;

private Runnable mDelayedSnapToPageRunnable;

private Point mDisplaySize = new Point();

private boolean mIsStaticWallpaper ;

private int mWallpaperTravelWidth ;

private int mSpringLoadedPageSpacing ;

private int mCameraDistance ;

mWallpaperManager = WallpaperManager.getInstance(context);

mWallpaperOffset = new WallpaperOffsetInterpolator();

mWallpaperTravelWidth = (int) (mDisplaySize. x * wallpaperTravelToScreenWidthRatio(mDisplaySize.x , mDisplaySize .y ));

mIsStaticWallpaper = mWallpaperManager.getWallpaperInfo() == null ;

方法和类:setWallpaperDimension()

wallpaperTravelToScreenWidthRatio()

wallpaperOffsetForCurrentScroll()

syncWallpaperOffsetWithScroll()

updateWallpaperOffsetImmediately()

updateWallpaperOffsets()

computeWallpaperScrollRatio()

WallpaperOffsetInterpolator类

可以说是WallpaperOffsetInterpolator负责壁纸滑动的,其他变量和方法为它服务。setWallpaperDimension()方法是设置壁纸的大小,这个方法在Launcher类初始化时候会调用。wallpaperOffsetForCurrentScroll()方法用于计算滑动壁纸需要移动的距离,它在syncWallpaperOffsetWithScroll()方法中调用,syncWallpaperOffsetWithScroll()方法很简单,如果手机开启硬件加速就执行WallpaperOffsetInterpolator的setFinalX方法,setFinalX方法再去调用wallpaperOffsetForCurrentScroll()方法。private void syncWallpaperOffsetWithScroll() {

final boolean enableWallpaperEffects = isHardwareAccelerated();

if (enableWallpaperEffects) {

mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll());

}

}

如果我们把enableWallpaperEffects值改为false会怎么样呢,没错就是固定不动的壁纸了。updateWallpaperOffsets()方法用于在ondraw

()方法中去更新视图(滑动的时候),配合在computeScroll()方法中调用syncWallpaperOffsetWithScroll()方法。@Override

public void computeScroll() {

super .computeScroll();

syncWallpaperOffsetWithScroll();

}

关于Launcher设置壁纸的流程就先介绍到这里,有疏漏的地方还请指正。有功能就会有Bug,那么一般关于壁纸常见的Bug有哪些呢?下一篇文章会具体介绍,有这样的经验的朋友欢迎一切探讨、交流。

android++设置壁纸,Android Launcher 设置壁纸相关推荐

  1. Android Launcher 设置壁纸

    版本:1.0  日期:2014.11.25 2014.11.26 版权:©kince 特别推荐:泡在网上的日子 一.概述 一般Launcher都带有壁纸设置的功能,Android提供了设置壁纸的API ...

  2. android4.1动态壁纸,Android 4.1 设置默认开机动态壁纸

    需要修改的文件为: 找到SourceCode/framework/base/core/res/res/values/config.xml中的: @null 包名/动态壁纸服务名 比如将默认壁纸更改为& ...

  3. android 壁纸服务,Android开发学习之WallPaper设置壁纸详细介绍与实例

    今天和大家分享的是关于在android中设置壁纸的方法,在android中设置壁纸的方法有三种,分别是: 1.使用wallpapermanager的setresource(int resourceid ...

  4. android设置主题背景为壁纸_如何为每个Android主屏幕添加不同的壁纸 | MOS86

    Android设备有很多不同的主屏幕.问题是,当您选择一个图像作为背景墙纸,它横跨所有3有时候没关系大多数时候,您想要看到的图像的一部分就在屏幕之间的裂缝上. 为了解决这个问题,您可以使用Multip ...

  5. Android设置来电壁纸,来电壁纸秀下载-来电壁纸秀 安卓版v1.0.7-PC6安卓网

    来电壁纸秀是一款特别炫酷的来电壁纸美化软件.来电壁纸秀app给大家准备了超级多的精美壁纸素材,来电壁纸秀不仅有无数的壁纸素材,而且来电壁纸秀app还有很多来电秀模板! 软件介绍 来电壁纸秀是一款来电秀 ...

  6. android 设置壁纸,Android 代码设置壁纸的方式,兼容各大ROM

    废话不多说,主要代码: public static void intent2SetWallPaper(Context context, String path) { Uri uriPath = get ...

  7. Launcher: 设置壁纸_源码跟踪

    网上有很多牛人研究 Launcher,说的都不错,但是个人还是觉得在技术方面还是各抒己见的为好,毕竟每个人研究的面不一样,借此,也想为自己做个笔记. 本博客主要是基于 android2.3.7 的源码 ...

  8. Android内置多个launcher设置默认launcher

    Android设置默认launcher 前言 高通 code MTK code 结语 前言 launcher因为开机即启动,若添加默认launcher过早则可能导致其他进程崩溃,添加过晚则起不到启动默 ...

  9. Android 内置多个launcher 设置默认launcher

    前言 launcher因为开机即启动,若添加默认launcher过早则可能导致其他进程崩溃,添加过晚则起不到启动默认 设置的效果且会弹出选择launcher的提示框. 查看了一些其他的修改方法,均需在 ...

最新文章

  1. 计算机网络是通信技术和,计算机网络是计算机技术和通信技术相结合的产物。()...
  2. Python 面向对象编程 day7
  3. java printf 版本_java – PrintStream类型中的printf(String,Object ...
  4. windows功能_你的Windows杀毒软件有这个功能吗?
  5. 2018网络统考计算机英语报名时间,2018年秋网络教育统考大学英语(B)考试样卷...
  6. drupal主题开发_Drupal开发人员,关于如何使您的网站更易于访问
  7. c++ 线程软件看门狗_装配生产线MES系统软件
  8. Android-JNI开发系列《五》局部引用全局引用全局弱引用缓存策略
  9. strcpy sprintf memcpy 它们之间的区别
  10. 564. 寻找最近的回文数
  11. Redis的安装教程(Windows+Linux)【超详细】
  12. 这就是艺术「GitHub 热点速览 v.22.25」
  13. 金桔智能门锁实现人证房三统一原理
  14. 酷开系统上线共抗疫情版块
  15. 移植u-boot到树莓派
  16. Excel如何快速在指定字符后面插入文本
  17. w ndows10专业版连接不上网,windows10系统电脑插着网线却连不上网如何解决
  18. 一级计算机页码居中,word中页码为何不能同时居中
  19. mysql停掉正在运行的存储过程
  20. Windows 7的应用程序兼容性和絮叨的应用程序兼容性助手

热门文章

  1. unity3d微端开发记录
  2. Qt-FFmpeg开发-实现录屏功能(10)
  3. 偏离策略年化收益回测出来了,高达372%
  4. 父元素中拖动子元素实现
  5. 综合组网实例配置 双出口双墙主备+三层核心VRRP+MSTP+NAT+NAT SERVER+AC+IPsec+广域网PPPOE+专线
  6. 我的2021考研之路(经验)分享
  7. animate动画使用
  8. 质数相关的算法 --Sieve of Eratosthenes算法 (埃拉托斯特尼)
  9. 机器学习时代的三大神器:GBDT,XGBOOST和LightGBM
  10. WF4.0实战(二):超市收银软件