summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornicolasroard <nicolasroard@google.com>2012-10-01 00:25:11 -0700
committernicolasroard <nicolasroard@google.com>2012-10-02 17:27:00 -0700
commite091f88847d6c1a142f3503a1d0d42f5ad0ba188 (patch)
tree463ac342c9cef88d60c1a1667c41a622a7c06d5f
parent1ebac746eb319663f44fe9fbb7786cb9bb87489b (diff)
downloadandroid_packages_apps_Snap-e091f88847d6c1a142f3503a1d0d42f5ad0ba188.tar.gz
android_packages_apps_Snap-e091f88847d6c1a142f3503a1d0d42f5ad0ba188.tar.bz2
android_packages_apps_Snap-e091f88847d6c1a142f3503a1d0d42f5ad0ba188.zip
Implements image sharing
bug:7233986 Change-Id: I8feb94d77facf8dbb8da5fab89b49ed7c224116e
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java67
-rw-r--r--src/com/android/gallery3d/filtershow/cache/ImageLoader.java15
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageShow.java6
-rw-r--r--src/com/android/gallery3d/filtershow/provider/SharedImageProvider.java123
-rw-r--r--src/com/android/gallery3d/filtershow/tools/ProcessedBitmap.java18
-rw-r--r--src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java94
6 files changed, 255 insertions, 68 deletions
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 4570eb017..b50ab94d6 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -1,6 +1,8 @@
package com.android.gallery3d.filtershow;
+import java.io.File;
+import java.io.IOException;
import java.util.Vector;
import com.android.gallery3d.filtershow.cache.ImageLoader;
@@ -10,6 +12,8 @@ import com.android.gallery3d.filtershow.imageshow.ImageShow;
import com.android.gallery3d.filtershow.imageshow.ImageSmallFilter;
import com.android.gallery3d.filtershow.imageshow.ImageStraighten;
import com.android.gallery3d.filtershow.presets.*;
+import com.android.gallery3d.filtershow.provider.SharedImageProvider;
+import com.android.gallery3d.filtershow.tools.SaveCopyTask;
import com.android.gallery3d.filtershow.ui.ImageCurves;
import com.android.gallery3d.R;
@@ -18,6 +22,7 @@ import android.os.Bundle;
import android.annotation.TargetApi;
import android.app.ActionBar;
import android.app.Activity;
+import android.content.ContentValues;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@@ -31,7 +36,6 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
-import android.widget.AbsoluteLayout;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
@@ -40,10 +44,13 @@ import android.widget.FrameLayout.LayoutParams;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListView;
+import android.widget.ShareActionProvider;
+import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
import android.widget.Toast;
@TargetApi(16)
-public class FilterShowActivity extends Activity implements OnItemClickListener {
+public class FilterShowActivity extends Activity implements OnItemClickListener,
+ OnShareTargetSelectedListener {
private ImageLoader mImageLoader = null;
private ImageShow mImageShow = null;
@@ -84,6 +91,11 @@ public class FilterShowActivity extends Activity implements OnItemClickListener
private Vector<ImageButton> mBottomPanelButtons = new Vector<ImageButton>();
private Vector<ImageButton> mColorsPanelButtons = new Vector<ImageButton>();
+ private ShareActionProvider mShareActionProvider;
+ private File mSharedOutputFile = null;
+
+ private boolean mSharingImage = false;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -210,6 +222,46 @@ public class FilterShowActivity extends Activity implements OnItemClickListener
}
}
+ public void completeSaveImage(Uri saveUri) {
+ if (mSharingImage && mSharedOutputFile != null) {
+ // Image saved, we unblock the content provider
+ Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
+ Uri.encode(mSharedOutputFile.getAbsolutePath()));
+ ContentValues values = new ContentValues();
+ values.put(SharedImageProvider.PREPARE, false);
+ getContentResolver().insert(uri, values);
+ }
+ setResult(RESULT_OK, new Intent().setData(saveUri));
+ finish();
+ }
+
+ @Override
+ public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) {
+ // First, let's tell the SharedImageProvider that it will need to wait for the image
+ Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
+ Uri.encode(mSharedOutputFile.getAbsolutePath()));
+ ContentValues values = new ContentValues();
+ values.put(SharedImageProvider.PREPARE, true);
+ getContentResolver().insert(uri, values);
+ mSharingImage = true;
+
+ // Process and save the image in the background.
+ mImageShow.saveImage(this, mSharedOutputFile);
+ return true;
+ }
+
+ private Intent getDefaultShareIntent() {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setType(SharedImageProvider.MIME_TYPE);
+ mSharedOutputFile = SaveCopyTask.getNewFile(this, mImageLoader.getUri());
+ Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI,
+ Uri.encode(mSharedOutputFile.getAbsolutePath()));
+ intent.putExtra(Intent.EXTRA_STREAM, uri);
+ return intent;
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu);
@@ -225,6 +277,10 @@ public class FilterShowActivity extends Activity implements OnItemClickListener
} else {
showState.setTitle(R.string.show_imagestate_panel);
}
+ mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share)
+ .getActionProvider();
+ mShareActionProvider.setShareIntent(getDefaultShareIntent());
+ mShareActionProvider.setOnShareTargetSelectedListener(this);
return true;
}
@@ -865,12 +921,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
- mImageShow.saveImage(this);
- }
-
- public void completeSaveImage(Uri saveUri) {
- setResult(RESULT_OK, new Intent().setData(saveUri));
- finish();
+ mImageShow.saveImage(this, null);
}
static {
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index 2c8fff9a2..100a17bf0 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -2,6 +2,7 @@
package com.android.gallery3d.filtershow.cache;
import java.io.Closeable;
+import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -13,6 +14,7 @@ import com.android.gallery3d.filtershow.HistoryAdapter;
import com.android.gallery3d.filtershow.imageshow.ImageShow;
import com.android.gallery3d.filtershow.presets.ImagePreset;
import com.android.gallery3d.filtershow.tools.SaveCopyTask;
+import com.android.gallery3d.filtershow.tools.ProcessedBitmap;
import com.android.gallery3d.R;
import android.content.Context;
@@ -59,6 +61,10 @@ public class ImageLoader {
updateBitmaps();
}
+ public Uri getUri() {
+ return mUri;
+ }
+
private int getOrientation(Uri uri) {
Cursor cursor = null;
try {
@@ -219,7 +225,8 @@ public class ImageLoader {
mCache.reset(imagePreset);
}
- public Uri saveImage(ImagePreset preset, final FilterShowActivity filterShowActivity) {
+ public Uri saveImage(ImagePreset preset, final FilterShowActivity filterShowActivity,
+ File destination) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
@@ -235,15 +242,15 @@ public class ImageLoader {
// TODO: on <3.x we need a copy of the bitmap (inMutable doesn't
// exist)
mSaveCopy = mFullOriginalBitmap;
- preset.apply(mSaveCopy);
- new SaveCopyTask(mContext, mUri, new SaveCopyTask.Callback() {
+ ProcessedBitmap processedBitmap = new ProcessedBitmap(mSaveCopy, preset);
+ new SaveCopyTask(mContext, mUri, destination, new SaveCopyTask.Callback() {
@Override
public void onComplete(Uri result) {
filterShowActivity.completeSaveImage(result);
}
- }).execute(mSaveCopy);
+ }).execute(processedBitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index 14bc0be20..2caa2d578 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -13,6 +13,8 @@ import com.android.gallery3d.R;
import com.android.gallery3d.R.id;
import com.android.gallery3d.R.layout;
+import java.io.File;
+
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -288,8 +290,8 @@ public class ImageShow extends View implements SliderListener {
mFilteredImage = bitmap;
}
- public void saveImage(FilterShowActivity filterShowActivity) {
- mImageLoader.saveImage(getImagePreset(), filterShowActivity);
+ public void saveImage(FilterShowActivity filterShowActivity, File file) {
+ mImageLoader.saveImage(getImagePreset(), filterShowActivity, file);
}
public boolean onTouchEvent(MotionEvent event) {
diff --git a/src/com/android/gallery3d/filtershow/provider/SharedImageProvider.java b/src/com/android/gallery3d/filtershow/provider/SharedImageProvider.java
new file mode 100644
index 000000000..dff15164b
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/provider/SharedImageProvider.java
@@ -0,0 +1,123 @@
+
+package com.android.gallery3d.filtershow.provider;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.ConditionVariable;
+import android.os.ParcelFileDescriptor;
+import android.provider.BaseColumns;
+import android.provider.MediaStore;
+import android.provider.OpenableColumns;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+
+public class SharedImageProvider extends ContentProvider {
+
+ private static final String LOGTAG = "SharedImageProvider";
+
+ public static final String MIME_TYPE = "image/jpeg";
+ public static final String AUTHORITY = "com.android.gallery3d.filtershow.provider.SharedImageProvider";
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/image");
+ public static final String PREPARE = "prepare";
+
+ private final String[] mMimeStreamType = {
+ MIME_TYPE
+ };
+
+ private static ConditionVariable mImageReadyCond = new ConditionVariable(false);
+
+ @Override
+ public int delete(Uri arg0, String arg1, String[] arg2) {
+ return 0;
+ }
+
+ @Override
+ public String getType(Uri arg0) {
+ return MIME_TYPE;
+ }
+
+ @Override
+ public String[] getStreamTypes(Uri arg0, String mimeTypeFilter) {
+ return mMimeStreamType;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ if (values.containsKey(PREPARE)) {
+ if (values.getAsBoolean(PREPARE)) {
+ mImageReadyCond.close();
+ } else {
+ mImageReadyCond.open();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
+ return 0;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+ String uriPath = uri.getLastPathSegment();
+ if (uriPath == null) {
+ return null;
+ }
+ if (projection == null) {
+ projection = new String[] {
+ BaseColumns._ID,
+ MediaStore.MediaColumns.DATA,
+ OpenableColumns.DISPLAY_NAME,
+ OpenableColumns.SIZE
+ };
+ }
+ // If we receive a query on display name or size,
+ // we should block until the image is ready
+ mImageReadyCond.block();
+
+ File path = new File(uriPath);
+
+ MatrixCursor cursor = new MatrixCursor(projection);
+ Object[] columns = new Object[projection.length];
+ for (int i = 0; i < projection.length; i++) {
+ if (projection[i].equalsIgnoreCase(BaseColumns._ID)) {
+ columns[i] = 0;
+ } else if (projection[i].equalsIgnoreCase(MediaStore.MediaColumns.DATA)) {
+ columns[i] = uri;
+ } else if (projection[i].equalsIgnoreCase(OpenableColumns.DISPLAY_NAME)) {
+ columns[i] = path.getName();
+ } else if (projection[i].equalsIgnoreCase(OpenableColumns.SIZE)) {
+ columns[i] = path.length();
+ }
+ }
+ cursor.addRow(columns);
+
+ return cursor;
+ }
+
+ public ParcelFileDescriptor openFile(Uri uri, String mode)
+ throws FileNotFoundException {
+ String uriPath = uri.getLastPathSegment();
+ if (uriPath == null) {
+ return null;
+ }
+ // Here we need to block until the image is ready
+ mImageReadyCond.block();
+ File path = new File(uriPath);
+ int imode = 0;
+ imode |= ParcelFileDescriptor.MODE_READ_ONLY;
+ return ParcelFileDescriptor.open(path, imode);
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/tools/ProcessedBitmap.java b/src/com/android/gallery3d/filtershow/tools/ProcessedBitmap.java
new file mode 100644
index 000000000..2e23b92eb
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/tools/ProcessedBitmap.java
@@ -0,0 +1,18 @@
+package com.android.gallery3d.filtershow.tools;
+
+import android.graphics.Bitmap;
+
+import com.android.gallery3d.filtershow.presets.ImagePreset;
+
+public class ProcessedBitmap {
+ private Bitmap mBitmap;
+ private ImagePreset mPreset;
+ public ProcessedBitmap(Bitmap bitmap, ImagePreset preset) {
+ mBitmap = bitmap;
+ mPreset = preset;
+ }
+ public Bitmap apply() {
+ mPreset.apply(mBitmap);
+ return mBitmap;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
index 8ca21e285..49cc33a2a 100644
--- a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
+++ b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
@@ -30,6 +30,8 @@ import android.provider.MediaStore.Images.ImageColumns;
import android.view.Gravity;
import android.widget.Toast;
+import com.android.gallery3d.filtershow.presets.ImagePreset;
+
//import com.android.gallery3d.R;
//import com.android.gallery3d.util.BucketNames;
@@ -45,46 +47,28 @@ import java.text.SimpleDateFormat;
/**
* Asynchronous task for saving edited photo as a new copy.
*/
-public class SaveCopyTask extends AsyncTask<Bitmap, Void, Uri> {
+public class SaveCopyTask extends AsyncTask<ProcessedBitmap, Void, Uri> {
public static final String DOWNLOAD = "download";
public static final String DEFAULT_SAVE_DIRECTORY = "Download";
private static final int DEFAULT_COMPRESS_QUALITY = 95;
/**
- * Saves the bitmap by given directory, filename, and format; if the
- * directory is given null, then saves it under the cache directory.
+ * Saves the bitmap in the final destination
*/
- public File saveBitmap(Bitmap bitmap, File directory, String filename,
- CompressFormat format) {
-
- if (directory == null) {
- directory = context.getCacheDir();
- } else {
- // Check if the given directory exists or try to create it.
- if (!directory.isDirectory() && !directory.mkdirs()) {
- return null;
- }
- }
-
- File file = null;
+ public static void saveBitmap(Bitmap bitmap, File destination) {
OutputStream os = null;
-
try {
- filename = (format == CompressFormat.PNG) ? filename + ".png"
- : filename + ".jpg";
- file = new File(directory, filename);
- os = new FileOutputStream(file);
- bitmap.compress(format, DEFAULT_COMPRESS_QUALITY, os);
+ os = new FileOutputStream(destination);
+ bitmap.compress(CompressFormat.JPEG, DEFAULT_COMPRESS_QUALITY, os);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
closeStream(os);
}
- return file;
}
- private void closeStream(Closeable stream) {
+ private static void closeStream(Closeable stream) {
if (stream != null) {
try {
stream.close();
@@ -113,62 +97,63 @@ public class SaveCopyTask extends AsyncTask<Bitmap, Void, Uri> {
private final Uri sourceUri;
private final Callback callback;
private final String saveFileName;
- private String saveFolderName;
+ private final File destinationFile;
- public SaveCopyTask(Context context, Uri sourceUri, Callback callback) {
+ public SaveCopyTask(Context context, Uri sourceUri, File destination, Callback callback) {
this.context = context;
this.sourceUri = sourceUri;
this.callback = callback;
+ if (destination == null) {
+ this.destinationFile = getNewFile(context, sourceUri);
+ } else {
+ this.destinationFile = destination;
+ }
+
saveFileName = new SimpleDateFormat(TIME_STAMP_NAME).format(new Date(
System.currentTimeMillis()));
}
+ public static File getNewFile(Context context, Uri sourceUri) {
+ File saveDirectory = getSaveDirectory(context, sourceUri);
+ if ((saveDirectory == null) || !saveDirectory.canWrite()) {
+ saveDirectory = new File(Environment.getExternalStorageDirectory(),
+ DOWNLOAD);
+ }
+
+ String filename = new SimpleDateFormat(TIME_STAMP_NAME).format(new Date(
+ System.currentTimeMillis()));
+ return new File(saveDirectory, filename + ".JPG");
+ }
+
/**
* The task should be executed with one given bitmap to be saved.
*/
@Override
- protected Uri doInBackground(Bitmap... params) {
+ protected Uri doInBackground(ProcessedBitmap... params) {
// TODO: Support larger dimensions for photo saving.
if (params[0] == null) {
return null;
}
- // Use the default save directory if the source directory cannot be
- // saved.
- File saveDirectory = getSaveDirectory();
- if ((saveDirectory == null) || !saveDirectory.canWrite()) {
- saveDirectory = new File(Environment.getExternalStorageDirectory(),
- DOWNLOAD);
- saveFolderName = DEFAULT_SAVE_DIRECTORY;
- } else {
- saveFolderName = saveDirectory.getName();
- }
- Bitmap bitmap = params[0];
+ ProcessedBitmap processedBitmap = params[0];
- File file = saveBitmap(bitmap, saveDirectory, saveFileName,
- Bitmap.CompressFormat.JPEG);
+ Bitmap bitmap = processedBitmap.apply();
+ saveBitmap(bitmap, this.destinationFile);
- Uri uri = (file != null) ? insertContent(file) : null;
+ Uri uri = insertContent(context, sourceUri, this.destinationFile, saveFileName);
bitmap.recycle();
return uri;
}
@Override
protected void onPostExecute(Uri result) {
- /*
- * String message = (result == null) ?
- * context.getString(R.string.saving_failure) :
- * context.getString(R.string.photo_saved, saveFolderName); Toast toast
- * = Toast.makeText(context, message, Toast.LENGTH_SHORT);
- * toast.setGravity(Gravity.CENTER, 0, 0); toast.show();
- */
if (callback != null) {
callback.onComplete(result);
}
}
- private void querySource(String[] projection,
+ private static void querySource(Context context, Uri sourceUri, String[] projection,
ContentResolverQueryCallback callback) {
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = null;
@@ -187,10 +172,10 @@ public class SaveCopyTask extends AsyncTask<Bitmap, Void, Uri> {
}
}
- private File getSaveDirectory() {
+ private static File getSaveDirectory(Context context, Uri sourceUri) {
final File[] dir = new File[1];
- querySource(new String[] {
- ImageColumns.DATA
+ querySource(context, sourceUri, new String[] {
+ ImageColumns.DATA
},
new ContentResolverQueryCallback() {
@@ -205,7 +190,7 @@ public class SaveCopyTask extends AsyncTask<Bitmap, Void, Uri> {
/**
* Insert the content (saved file) with proper source photo properties.
*/
- private Uri insertContent(File file) {
+ public static Uri insertContent(Context context, Uri sourceUri, File file, String saveFileName) {
long now = System.currentTimeMillis() / 1000;
final ContentValues values = new ContentValues();
@@ -223,7 +208,7 @@ public class SaveCopyTask extends AsyncTask<Bitmap, Void, Uri> {
ImageColumns.DATE_TAKEN,
ImageColumns.LATITUDE, ImageColumns.LONGITUDE,
};
- querySource(projection, new ContentResolverQueryCallback() {
+ querySource(context, sourceUri, projection, new ContentResolverQueryCallback() {
@Override
public void onCursorResult(Cursor cursor) {
@@ -243,4 +228,5 @@ public class SaveCopyTask extends AsyncTask<Bitmap, Void, Uri> {
return context.getContentResolver().insert(
Images.Media.EXTERNAL_CONTENT_URI, values);
}
+
}