From a5aa75d6ac958822e145b61e7c475bd1dc1b5260 Mon Sep 17 00:00:00 2001 From: Danesh M Date: Wed, 9 Sep 2015 17:51:27 -0700 Subject: Gallery3d : Fix CROP_ACTION for third party apps Certain apps such as google photos, don't respect return-data true, since the bitmap could be very large. Switch to a file provider to pass the external apps a uri to write cropped results to. Change-Id: I9ec8b8defaffa3d9fa0c2cdfd68422eeff5aef84 --- AndroidManifest.xml | 9 ++ res/xml/file_paths.xml | 18 +++ slim_manifest/AndroidManifest.xml | 10 +- .../gallery3d/filtershow/cache/ImageLoader.java | 2 +- .../android/gallery3d/gadget/WidgetConfigure.java | 176 +++++++++++++++++---- 5 files changed, 179 insertions(+), 36 deletions(-) create mode 100644 res/xml/file_paths.xml diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 88a218ca8..216996017 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -436,5 +436,14 @@ android:label="@string/movie_view_label" android:configChanges="orientation|keyboardHidden|screenSize|mnc|mcc"> + + + diff --git a/res/xml/file_paths.xml b/res/xml/file_paths.xml new file mode 100644 index 000000000..28d186477 --- /dev/null +++ b/res/xml/file_paths.xml @@ -0,0 +1,18 @@ + + + + diff --git a/slim_manifest/AndroidManifest.xml b/slim_manifest/AndroidManifest.xml index e515319e9..aae3467bc 100644 --- a/slim_manifest/AndroidManifest.xml +++ b/slim_manifest/AndroidManifest.xml @@ -233,6 +233,14 @@ - + + + diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java index ea559e569..30d535d77 100644 --- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java +++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java @@ -108,7 +108,7 @@ public final class ImageLoader { new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null); if (cursor != null && cursor.moveToNext()) { - int ori = cursor.getInt(0); + int ori = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.ORIENTATION); switch (ori) { case 90: return ORI_ROTATE_90; diff --git a/src/com/android/gallery3d/gadget/WidgetConfigure.java b/src/com/android/gallery3d/gadget/WidgetConfigure.java index 2a4c6cfe4..b9a3fec23 100644 --- a/src/com/android/gallery3d/gadget/WidgetConfigure.java +++ b/src/com/android/gallery3d/gadget/WidgetConfigure.java @@ -18,11 +18,16 @@ package com.android.gallery3d.gadget; import android.app.Activity; import android.appwidget.AppWidgetManager; +import android.content.ClipData; import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; +import android.provider.MediaStore; +import android.support.v4.content.FileProvider; import android.util.Log; import android.widget.RemoteViews; @@ -38,6 +43,14 @@ import com.android.gallery3d.data.Path; import com.android.gallery3d.filtershow.crop.CropActivity; import com.android.gallery3d.filtershow.crop.CropExtras; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + public class WidgetConfigure extends Activity { @SuppressWarnings("unused") private static final String TAG = "WidgetConfigure"; @@ -61,6 +74,7 @@ public class WidgetConfigure extends Activity { private int mAppWidgetId = -1; private Uri mPickedItem; + private Uri mCropSrc, mCropDst; @Override protected void onCreate(Bundle savedState) { @@ -116,48 +130,142 @@ public class WidgetConfigure extends Activity { } else if (requestCode == REQUEST_GET_PHOTO) { setChoosenPhoto(data); } else if (requestCode == REQUEST_CROP_IMAGE) { - setPhotoWidget(data); + setPhotoWidget(); } else { throw new AssertionError("unknown request: " + requestCode); } } - private void setPhotoWidget(Intent data) { - // Store the cropped photo in our database - Bitmap bitmap = (Bitmap) data.getParcelableExtra("data"); - WidgetDatabaseHelper helper = new WidgetDatabaseHelper(this); + private void setPhotoWidget() { + AsyncTask.execute(new Runnable() { + @Override + public void run() { + Bitmap bitmap = null; + InputStream stream = null; + try { + stream = WidgetConfigure.this.getContentResolver() + .openInputStream(mCropDst); + if (stream != null) { + bitmap = BitmapFactory.decodeStream(stream); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + getContentResolver().delete(mCropSrc, null, null); + getContentResolver().delete(mCropDst, null, null); + } + if (bitmap == null) { + setResult(Activity.RESULT_CANCELED); + finish(); + return; + } + WidgetDatabaseHelper helper = new WidgetDatabaseHelper(WidgetConfigure.this); + try { + helper.setPhoto(mAppWidgetId, mPickedItem, bitmap); + updateWidgetAndFinish(helper.getEntry(mAppWidgetId)); + } finally { + helper.close(); + } + } + }); + } + + private void setChoosenPhoto(final Intent data) { + AsyncTask.execute(new Runnable() { + @Override + public void run() { + Resources res = getResources(); + + float width = res.getDimension(R.dimen.appwidget_width); + float height = res.getDimension(R.dimen.appwidget_height); + + // We try to crop a larger image (by scale factor), but there is still + // a bound on the binder limit. + float scale = Math.min(WIDGET_SCALE_FACTOR, + MAX_WIDGET_SIDE / Math.max(width, height)); + + int widgetWidth = Math.round(width * scale); + int widgetHeight = Math.round(height * scale); + + File cropSrc = new File(getCacheDir(), "crop_source.png"); + File cropDst = new File(getCacheDir(), "crop_dest.png"); + mPickedItem = data.getData(); + if (!copyUriToFile(mPickedItem, cropSrc)) { + setResult(Activity.RESULT_CANCELED); + finish(); + return; + } + + mCropSrc = FileProvider.getUriForFile(WidgetConfigure.this, + "com.android.gallery3d.fileprovider", + new File(cropSrc.getAbsolutePath())); + mCropDst = FileProvider.getUriForFile(WidgetConfigure.this, + "com.android.gallery3d.fileprovider", + new File(cropDst.getAbsolutePath())); + + Intent request = new Intent(CropActivity.CROP_ACTION) + .putExtra(CropExtras.KEY_OUTPUT_X, widgetWidth) + .putExtra(CropExtras.KEY_OUTPUT_Y, widgetHeight) + .putExtra(CropExtras.KEY_ASPECT_X, widgetWidth) + .putExtra(CropExtras.KEY_ASPECT_Y, widgetHeight) + .putExtra(CropExtras.KEY_SCALE_UP_IF_NEEDED, true) + .putExtra(CropExtras.KEY_SCALE, true) + .putExtra(CropExtras.KEY_RETURN_DATA, false) + .setDataAndType(mCropSrc, "image/*") + .addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | + Intent.FLAG_GRANT_READ_URI_PERMISSION); + request.putExtra(MediaStore.EXTRA_OUTPUT, mCropDst); + request.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, mCropDst)); + startActivityForResult(request, REQUEST_CROP_IMAGE); + } + }); + } + + public boolean copyUriToFile(Uri inUri, File dst) { + boolean isSuccessful = false; + InputStream in = null; + OutputStream out = null; try { - helper.setPhoto(mAppWidgetId, mPickedItem, bitmap); - updateWidgetAndFinish(helper.getEntry(mAppWidgetId)); + in = getContentResolver().openInputStream(inUri); + out = new FileOutputStream(dst); + + byte[] buf = new byte[1024]; + + try { + for (int len; (len = in.read(buf)) > 0; ) { + out.write(buf, 0, len); + } + isSuccessful = true; + } catch (IOException e) { + // ignore + } + + } catch (FileNotFoundException fnf) { + // ignore } finally { - helper.close(); + if (in != null) { + try { + in.close(); + } catch (IOException e) { + // ignore + } + } + if (out != null) { + try { + out.close(); + } catch (IOException e) { + // ignore + } + } } - } - - private void setChoosenPhoto(Intent data) { - Resources res = getResources(); - - float width = res.getDimension(R.dimen.appwidget_width); - float height = res.getDimension(R.dimen.appwidget_height); - - // We try to crop a larger image (by scale factor), but there is still - // a bound on the binder limit. - float scale = Math.min(WIDGET_SCALE_FACTOR, - MAX_WIDGET_SIDE / Math.max(width, height)); - - int widgetWidth = Math.round(width * scale); - int widgetHeight = Math.round(height * scale); - - mPickedItem = data.getData(); - Intent request = new Intent(CropActivity.CROP_ACTION, mPickedItem) - .putExtra(CropExtras.KEY_OUTPUT_X, widgetWidth) - .putExtra(CropExtras.KEY_OUTPUT_Y, widgetHeight) - .putExtra(CropExtras.KEY_ASPECT_X, widgetWidth) - .putExtra(CropExtras.KEY_ASPECT_Y, widgetHeight) - .putExtra(CropExtras.KEY_SCALE_UP_IF_NEEDED, true) - .putExtra(CropExtras.KEY_SCALE, true) - .putExtra(CropExtras.KEY_RETURN_DATA, true); - startActivityForResult(request, REQUEST_CROP_IMAGE); + return isSuccessful; } private void setChoosenAlbum(Intent data) { -- cgit v1.2.3