这两天都在解个bug,widget相关的,打开menu--->add--->widget--->FileManageer or Gallery.
bug现象:
这时,Gallery 能正常打开CropImage.java, 可以实现截图,在桌面正确生成一个图片;但是FileManager打开是,在桌面生成的是一个黑图。
先发patch吧,看了就明白了。
--- a/src/com/windriver/filemanager/FileManagerActivity.java
+++ b/src/com/windriver/filemanager/FileManagerActivity.java
@@ -16,6 +16,8 @@
package com.windriver.filemanager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Context;
@@ -78,6 +80,8 @@ public class FileManagerActivity extends ListActivity implements OnClickListener
private TextView mTextPath;
private Button mButtonBack;
+// private Bitmap image;
+
private String mPath;
private String mRootPath;
private String mAction;
@@ -189,10 +193,24 @@ public class FileManagerActivity extends ListActivity implements OnClickListener
if(action.equals(Intent.ACTION_MAIN)){
showInfo(f);
} else if (action.equals(Intent.ACTION_GET_CONTENT)){
- Uri uri = Uri.fromFile(f);
- Log.v(TAG, "uri = " + uri.toString());
- setResult(RESULT_OK, new Intent().setData(uri));
- finish();
+ Bundle myExtras = intent.getExtras();
+ if (myExtras != null && (myExtras.getParcelable("data") != null || myExtras.getBoolean("return-data"))) {
+
+ try {
+ Bitmap image = BitmapFactory.decodeFile(mPath + "/" +name); //打开sd卡中的图片,生成image。
+ Bitmap mBitmap = Bitmap.createBitmap(image,0,0,120,120); //缩放图片image,生成120x120的小图片,因为图片太大了,传不到widget里去。
+ image.recycle(); //用完回收内存。
+ Bundle extras = new Bundle();
+ extras.putParcelable("data", mBitmap); //发送的内容。
+ setResult(RESULT_OK, (new Intent()).setAction("inline-data").putExtras(extras)); //发送信号inline-data,表示可以接收了。
+ } catch (Exception ex) {
+ }
+ } else {
+ Uri uri = Uri.fromFile(f);
+ Log.v(TAG, "uri = " + uri.toString());
+ setResult(RESULT_OK, new Intent().setData(uri));
+ }
+ finish();
}
}
}
--
调试过程:先是看了 FileManager
vendor/wrs/addons/FileManager 里面的代码,知道了FileManager的工作原理。
然后看 packages/apps/Gallery3D/里面的内容,其中:
packages/apps/Gallery3D/src/com/cooliris/media/CropImage.java
因为打开Widget --->Gallery后,就进入CropImage.
里面的重要信息是:
private void onSaveClicked() {
// CR: TODO!
// TODO this code needs to change to use the decode/crop/encode single
// step api so that we don't require that the whole (possibly large)
// bitmap doesn't have to be read into memory
if (mSaving)
return;
if (mCrop == null) {
return;
}
mSaving = true;
Rect r = mCrop.getCropRect();
int width = r.width(); // CR: final == happy panda!
int height = r.height();
// If we are circle cropping, we want alpha channel, which is the
// third param here.
Bitmap croppedImage = Bitmap.createBitmap(width, height, mCircleCrop ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
{
Canvas canvas = new Canvas(croppedImage);
Rect dstRect = new Rect(0, 0, width, height);
canvas.drawBitmap(mBitmap, r, dstRect, null);
}
if (mCircleCrop) {
// OK, so what's all this about?
// Bitmaps are inherently rectangular but we want to return
// something that's basically a circle. So we fill in the
// area around the circle with alpha. Note the all important
// PortDuff.Mode.CLEAR.
Canvas c = new Canvas(croppedImage);
Path p = new Path();
p.addCircle(width / 2F, height / 2F, width / 2F, Path.Direction.CW);
c.clipPath(p, Region.Op.DIFFERENCE);
c.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
}
// If the output is required to a specific size then scale or fill.
if (mOutputX != 0 && mOutputY != 0) {
if (mScale) {
// Scale the image to the required dimensions.
Bitmap old = croppedImage;
croppedImage = Util.transform(new Matrix(), croppedImage, mOutputX, mOutputY, mScaleUp);
if (old != croppedImage) {
old.recycle();
}
} else {
/*
* Don't scale the image crop it to the size requested. Create
* an new image with the cropped image in the center and the
* extra space filled.
*/
// Don't scale the image but instead fill it so it's the
// required dimension
Bitmap b = Bitmap.createBitmap(mOutputX, mOutputY, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(b);
Rect srcRect = mCrop.getCropRect();
Rect dstRect = new Rect(0, 0, mOutputX, mOutputY);
int dx = (srcRect.width() - dstRect.width()) / 2;
int dy = (srcRect.height() - dstRect.height()) / 2;
// If the srcRect is too big, use the center part of it.
srcRect.inset(Math.max(0, dx), Math.max(0, dy));
// If the dstRect is too big, use the center part of it.
dstRect.inset(Math.max(0, -dx), Math.max(0, -dy));
// Draw the cropped bitmap in the center.
canvas.drawBitmap(mBitmap, srcRect, dstRect, null);
// Set the cropped bitmap as the new bitmap.
croppedImage.recycle();
croppedImage = b;
}
}
// Return the cropped image directly or save it to the specified URI.
Bundle myExtras = getIntent().getExtras();
if (myExtras != null && (myExtras.getParcelable("data") != null || myExtras.getBoolean("return-data"))) {
Bundle extras = new Bundle();
extras.putParcelable("data", croppedImage);
setResult(RESULT_OK, (new Intent()).setAction("inline-data").putExtras(extras)); //这段实现了发送widget图片的机制。
finish();
} else {
final Bitmap b = croppedImage;
final Runnable save = new Runnable() {
public void run() {
saveOutput(b);
}
};
Util.startBackgroundJob(this, null, getResources().getString(R.string.saving_image), save, mHandler);
}
}
这样就把问题解决了。
但是解决之前,走了不少弯路,如下:
点开Widget,先运行AppWidgetPickActivity:
packages/apps/Settings/src/com/android/settings/AppWidgetPickActivity.java
就是选择widget 选项,这里选择photo frame.
然后进入PhotoAppWidgetProvider and PhotoAppWidgetConfigure.java :
packages/apps/Gallery3D/src/com/cooliris/media/PhotoAppWidgetProvider.java
packages/apps/Gallery3D/src/com/cooliris/media/PhotoAppWidgetConfigure.java
这里有个重要的类:
static class PhotoDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "launcher.db";
private static final int DATABASE_VERSION = 2;
static final String TABLE_PHOTOS = "photos";
static final String FIELD_APPWIDGET_ID = "appWidgetId";
static final String FIELD_PHOTO_BLOB = "photoBlob";
PhotoDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
在PhotoAppWidgetConfigure.java中会用到,如下:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && mAppWidgetId != -1) {
// Store the cropped photo in our database
Bitmap bitmap = (Bitmap) data.getParcelableExtra("data");
PhotoDatabaseHelper helper = new PhotoDatabaseHelper(this);
if (helper.setPhoto(mAppWidgetId, bitmap)) {
resultCode = Activity.RESULT_OK;
// Push newly updated widget to surface
RemoteViews views PhotoAppWidgetProvider=.buildUpdate(this, mAppWidgetId, helper);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
appWidgetManager.updateAppWidget(new int[] { mAppWidgetId }, views);
}
helper.close();
} else {
resultCode = Activity.RESULT_CANCELED;
}
// Make sure we pass back the original mAppWidgetId
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(resultCode, resultValue);
finish();
}
开始一直以为是这里进行图片返回,一直没弄出来。这里涉及framework里的一个widget类,AppWidgetManager:
frameworks/base/core/java/android/appwidget/AppWidgetManager.java
这之后就让选择 Gallery 或者 FileManager. 运行相应的程序了。