Merge "Fix 5481444 Face clustering should use PWA profile shot instead of random photo" into ics-mr1
diff --git a/src/com/android/gallery3d/app/AbstractGalleryActivity.java b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
index 0fde9cc..d25f60e 100644
--- a/src/com/android/gallery3d/app/AbstractGalleryActivity.java
+++ b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
@@ -68,6 +68,7 @@
public void onConfigurationChanged(Configuration config) {
super.onConfigurationChanged(config);
mStateManager.onConfigurationChange(config);
+ invalidateOptionsMenu();
}
public Context getAndroidContext() {
diff --git a/src/com/android/gallery3d/app/AlbumPage.java b/src/com/android/gallery3d/app/AlbumPage.java
index eecb8e2..10c2b67 100644
--- a/src/com/android/gallery3d/app/AlbumPage.java
+++ b/src/com/android/gallery3d/app/AlbumPage.java
@@ -17,7 +17,6 @@
package com.android.gallery3d.app;
import android.app.Activity;
-import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -73,6 +72,9 @@
private static final int REQUEST_PHOTO = 2;
private static final int REQUEST_DO_ANIMATION = 3;
+ private static final int BIT_LOADING_RELOAD = 1;
+ private static final int BIT_LOADING_SYNC = 2;
+
private static final float USER_DISTANCE_METER = 0.3f;
private boolean mIsActive = false;
@@ -99,11 +101,11 @@
private boolean mShowDetails;
private float mUserDistance; // in pixel
- private ProgressDialog mProgressDialog;
- private Future<?> mPendingTask;
-
private Future<Integer> mSyncTask = null;
+ private int mLoadingBits = 0;
+ private boolean mInitialSynced = false;
+
private final GLView mRootPane = new GLView() {
private final float mMatrix[] = new float[16];
@@ -175,23 +177,16 @@
if (mGetContent) {
onGetContent(item);
} else {
- boolean playVideo =
- (item.getSupportedOperations() & MediaItem.SUPPORT_PLAY) != 0;
- if (playVideo) {
- // Play the video.
- PhotoPage.playVideo((Activity) mActivity, item.getPlayUri(), item.getName());
- } else {
- // Get into the PhotoPage.
- Bundle data = new Bundle();
- mAlbumView.savePositions(PositionRepository.getInstance(mActivity));
- data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex);
- data.putString(PhotoPage.KEY_MEDIA_SET_PATH,
- mMediaSetPath.toString());
- data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH,
- item.getPath().toString());
- mActivity.getStateManager().startStateForResult(
- PhotoPage.class, REQUEST_PHOTO, data);
- }
+ // Get into the PhotoPage.
+ Bundle data = new Bundle();
+ mAlbumView.savePositions(PositionRepository.getInstance(mActivity));
+ data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex);
+ data.putString(PhotoPage.KEY_MEDIA_SET_PATH,
+ mMediaSetPath.toString());
+ data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH,
+ item.getPath().toString());
+ mActivity.getStateManager().startStateForResult(
+ PhotoPage.class, REQUEST_PHOTO, data);
}
} else {
mSelectionManager.toggle(item.getPath());
@@ -333,6 +328,10 @@
mAlbumDataAdapter.resume();
mAlbumView.resume();
mActionModeHandler.resume();
+ if (!mInitialSynced) {
+ mSyncTask = mMediaSet.requestSync(this);
+ setLoadingBit(BIT_LOADING_SYNC);
+ }
}
@Override
@@ -342,16 +341,7 @@
mAlbumDataAdapter.pause();
mAlbumView.pause();
DetailsHelper.pause();
- Future<?> task = mPendingTask;
- if (task != null) {
- // cancel on going task
- task.cancel();
- task.waitDone();
- if (mProgressDialog != null) {
- mProgressDialog.dismiss();
- mProgressDialog = null;
- }
- }
+
if (mSyncTask != null) {
mSyncTask.cancel();
mSyncTask = null;
@@ -575,9 +565,11 @@
((Activity) mActivity).runOnUiThread(new Runnable() {
@Override
public void run() {
+ if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) {
+ mInitialSynced = true;
+ }
if (!mIsActive) return;
- mediaSet.notifyContentChanged(); // force reload to handle spinner
-
+ clearLoadingBit(BIT_LOADING_SYNC);
if (resultCode == MediaSet.SYNC_RESULT_ERROR) {
Toast.makeText((Context) mActivity, R.string.sync_album_error,
Toast.LENGTH_LONG).show();
@@ -586,33 +578,42 @@
});
}
+ private void setLoadingBit(int loadTaskBit) {
+ if (mLoadingBits == 0) {
+ GalleryUtils.setSpinnerVisibility((Activity) mActivity, true);
+ }
+ mLoadingBits |= loadTaskBit;
+ }
+
+ private void clearLoadingBit(int loadTaskBit) {
+ mLoadingBits &= ~loadTaskBit;
+ if (mLoadingBits == 0) {
+ GalleryUtils.setSpinnerVisibility((Activity) mActivity, false);
+
+ if (mAlbumDataAdapter.size() == 0) {
+ Toast.makeText((Context) mActivity,
+ R.string.empty_album, Toast.LENGTH_LONG).show();
+ mActivity.getStateManager().finishState(AlbumPage.this);
+ }
+ }
+ }
+
private class MyLoadingListener implements LoadingListener {
@Override
public void onLoadingStarted() {
- GalleryUtils.setSpinnerVisibility((Activity) mActivity, true);
+ setLoadingBit(BIT_LOADING_RELOAD);
}
@Override
public void onLoadingFinished() {
if (!mIsActive) return;
- if (mAlbumDataAdapter.size() == 0) {
- if (mSyncTask == null) {
- mSyncTask = mMediaSet.requestSync(AlbumPage.this);
- }
- if (mSyncTask.isDone()){
- Toast.makeText((Context) mActivity,
- R.string.empty_album, Toast.LENGTH_LONG).show();
- mActivity.getStateManager().finishState(AlbumPage.this);
- }
- }
- if (mSyncTask == null || mSyncTask.isDone()) {
- GalleryUtils.setSpinnerVisibility((Activity) mActivity, false);
- }
+ clearLoadingBit(BIT_LOADING_RELOAD);
}
}
private class MyDetailsSource implements DetailsHelper.DetailsSource {
private int mIndex;
+
public int size() {
return mAlbumDataAdapter.size();
}
diff --git a/src/com/android/gallery3d/app/AlbumSetPage.java b/src/com/android/gallery3d/app/AlbumSetPage.java
index b7e0097..c31e920 100644
--- a/src/com/android/gallery3d/app/AlbumSetPage.java
+++ b/src/com/android/gallery3d/app/AlbumSetPage.java
@@ -43,7 +43,6 @@
import com.android.gallery3d.ui.AlbumSetView;
import com.android.gallery3d.ui.DetailsHelper;
import com.android.gallery3d.ui.DetailsHelper.CloseListener;
-import com.android.gallery3d.util.GalleryUtils;
import com.android.gallery3d.ui.GLCanvas;
import com.android.gallery3d.ui.GLView;
import com.android.gallery3d.ui.GridDrawer;
@@ -55,6 +54,7 @@
import com.android.gallery3d.ui.SlotView;
import com.android.gallery3d.ui.StaticBackground;
import com.android.gallery3d.util.Future;
+import com.android.gallery3d.util.GalleryUtils;
public class AlbumSetPage extends ActivityState implements
SelectionManager.SelectionListener, GalleryActionBar.ClusterRunner,
@@ -70,6 +70,9 @@
private static final int DATA_CACHE_SIZE = 256;
private static final int REQUEST_DO_ANIMATION = 1;
+ private static final int BIT_LOADING_RELOAD = 1;
+ private static final int BIT_LOADING_SYNC = 2;
+
private boolean mIsActive = false;
private StaticBackground mStaticBackground;
private AlbumSetView mAlbumSetView;
@@ -103,6 +106,9 @@
private Future<Integer> mSyncTask = null;
+ private int mLoadingBits = 0;
+ private boolean mInitialSynced = false;
+
private final GLView mRootPane = new GLView() {
private final float mMatrix[] = new float[16];
@@ -284,6 +290,30 @@
startTransition();
}
+ private void clearLoadingBit(int loadingBit) {
+ mLoadingBits &= ~loadingBit;
+ if (mLoadingBits == 0) {
+ GalleryUtils.setSpinnerVisibility((Activity) mActivity, false);
+
+ // Only show toast when there's no album and we are going to finish
+ // the page. Toast is redundant if we are going to stay on this page.
+ if ((mAlbumSetDataAdapter.size() == 0)) {
+ Toast.makeText((Context) mActivity,
+ R.string.empty_album, Toast.LENGTH_LONG).show();
+ if (mActivity.getStateManager().getStateCount() > 1) {
+ mActivity.getStateManager().finishState(this);
+ }
+ }
+ }
+ }
+
+ private void setLoadingBit(int loadingBit) {
+ if (mLoadingBits == 0) {
+ GalleryUtils.setSpinnerVisibility((Activity) mActivity, true);
+ }
+ mLoadingBits |= loadingBit;
+ }
+
@Override
public void onPause() {
super.onPause();
@@ -298,6 +328,7 @@
if (mSyncTask != null) {
mSyncTask.cancel();
mSyncTask = null;
+ clearLoadingBit(BIT_LOADING_SYNC);
}
}
@@ -314,6 +345,10 @@
if (mShowClusterMenu && actionBar != null) {
actionBar.showClusterMenu(mSelectedAction, this);
}
+ if (!mInitialSynced) {
+ mSyncTask = mMediaSet.requestSync(AlbumSetPage.this);
+ setLoadingBit(BIT_LOADING_SYNC);
+ }
}
private void initializeData(Bundle data) {
@@ -571,9 +606,11 @@
((Activity) mActivity).runOnUiThread(new Runnable() {
@Override
public void run() {
+ if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) {
+ mInitialSynced = true;
+ }
if (!mIsActive) return;
- mediaSet.notifyContentChanged(); // force reload to handle spinner
-
+ clearLoadingBit(BIT_LOADING_SYNC);
if (resultCode == MediaSet.SYNC_RESULT_ERROR) {
Toast.makeText((Context) mActivity, R.string.sync_album_set_error,
Toast.LENGTH_LONG).show();
@@ -584,29 +621,12 @@
private class MyLoadingListener implements LoadingListener {
public void onLoadingStarted() {
- GalleryUtils.setSpinnerVisibility((Activity) mActivity, true);
+ setLoadingBit(BIT_LOADING_RELOAD);
}
public void onLoadingFinished() {
if (!mIsActive) return;
-
- if (mSyncTask == null) {
- // Request sync in case the mediaSet hasn't been sync'ed before.
- mSyncTask = mMediaSet.requestSync(AlbumSetPage.this);
- }
- if (mSyncTask.isDone()){
- // The mediaSet is in sync. Turn off the loading indicator.
- GalleryUtils.setSpinnerVisibility((Activity) mActivity, false);
-
- // Only show toast when there's no album and we are going to finish
- // the page. Toast is redundant if we are going to stay on this page.
- if ((mAlbumSetDataAdapter.size() == 0)
- && (mActivity.getStateManager().getStateCount() > 1)) {
- Toast.makeText((Context) mActivity,
- R.string.empty_album, Toast.LENGTH_LONG).show();
- mActivity.getStateManager().finishState(AlbumSetPage.this);
- }
- }
+ clearLoadingBit(BIT_LOADING_RELOAD);
}
}
diff --git a/src/com/android/gallery3d/app/MoviePlayer.java b/src/com/android/gallery3d/app/MoviePlayer.java
index 07fe71a..9c81c79 100644
--- a/src/com/android/gallery3d/app/MoviePlayer.java
+++ b/src/com/android/gallery3d/app/MoviePlayer.java
@@ -16,11 +16,6 @@
package com.android.gallery3d.app;
-import com.android.gallery3d.R;
-import com.android.gallery3d.common.BlobCache;
-import com.android.gallery3d.util.CacheManager;
-import com.android.gallery3d.util.GalleryUtils;
-
import android.app.ActionBar;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
@@ -35,13 +30,16 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
-import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.MediaController;
import android.widget.VideoView;
+import com.android.gallery3d.R;
+import com.android.gallery3d.common.BlobCache;
+import com.android.gallery3d.util.CacheManager;
+import com.android.gallery3d.util.GalleryUtils;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -162,7 +160,8 @@
}
private void showSystemUi(boolean visible) {
- int flag = visible ? 0 : View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ int flag = visible ? 0 : View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_LOW_PROFILE;
mVideoView.setSystemUiVisibility(flag);
}
@@ -348,9 +347,7 @@
@Override
public void onReceive(Context context, Intent intent) {
- if (mVideoView.isPlaying()) {
- mVideoView.pause();
- }
+ if (mVideoView.isPlaying()) pauseVideo();
}
}
}
diff --git a/src/com/android/gallery3d/photoeditor/EffectsBar.java b/src/com/android/gallery3d/photoeditor/EffectsBar.java
index acb22b6..4075404 100644
--- a/src/com/android/gallery3d/photoeditor/EffectsBar.java
+++ b/src/com/android/gallery3d/photoeditor/EffectsBar.java
@@ -67,8 +67,6 @@
return select;
}
});
-
- setEnabled(false);
}
private void createEffectsGallery(int effectsId) {
@@ -130,13 +128,12 @@
private boolean exitActiveEffect(final Runnable runnableOnDone) {
if (activeEffect != null) {
- final SpinnerProgressDialog progressDialog = SpinnerProgressDialog.show(
- (ViewGroup) getRootView().findViewById(R.id.toolbar));
+ SpinnerProgressDialog.showDialog();
activeEffect.end(new Runnable() {
@Override
public void run() {
- progressDialog.dismiss();
+ SpinnerProgressDialog.dismissDialog();
View fullscreenTool = getRootView().findViewById(R.id.fullscreen_effect_tool);
if (fullscreenTool != null) {
((ViewGroup) fullscreenTool.getParent()).removeView(fullscreenTool);
diff --git a/src/com/android/gallery3d/photoeditor/FilterStack.java b/src/com/android/gallery3d/photoeditor/FilterStack.java
index 7a15509..fe6fb10 100644
--- a/src/com/android/gallery3d/photoeditor/FilterStack.java
+++ b/src/com/android/gallery3d/photoeditor/FilterStack.java
@@ -17,9 +17,11 @@
package com.android.gallery3d.photoeditor;
import android.graphics.Bitmap;
+import android.os.Bundle;
import com.android.gallery3d.photoeditor.filters.Filter;
+import java.util.ArrayList;
import java.util.Stack;
/**
@@ -35,6 +37,9 @@
void onStackChanged(boolean canUndo, boolean canRedo);
}
+ private static final String APPLIED_STACK_KEY = "applied_stack";
+ private static final String REDO_STACK_KEY = "redo_stack";
+
private final Stack<Filter> appliedStack = new Stack<Filter>();
private final Stack<Filter> redoStack = new Stack<Filter>();
@@ -45,12 +50,28 @@
private Photo source;
private Runnable queuedTopFilterChange;
- private boolean topFilterOutputted;
+ private boolean outputTopFilter;
private volatile boolean paused;
- public FilterStack(PhotoView photoView, StackListener stackListener) {
+ public FilterStack(PhotoView photoView, StackListener stackListener, Bundle savedState) {
this.photoView = photoView;
this.stackListener = stackListener;
+ if (savedState != null) {
+ appliedStack.addAll(getFilters(savedState, APPLIED_STACK_KEY));
+ redoStack.addAll(getFilters(savedState, REDO_STACK_KEY));
+ outputTopFilter = true;
+ stackListener.onStackChanged(!appliedStack.empty(), !redoStack.empty());
+ }
+ }
+
+ private ArrayList<Filter> getFilters(Bundle savedState, String key) {
+ // Infer Filter array-list from the Parcelable array-list by the specified returned type.
+ return savedState.getParcelableArrayList(key);
+ }
+
+ public void saveStacks(Bundle outState) {
+ outState.putParcelableArrayList(APPLIED_STACK_KEY, new ArrayList<Filter>(appliedStack));
+ outState.putParcelableArrayList(REDO_STACK_KEY, new ArrayList<Filter>(redoStack));
}
private void reallocateBuffer(int target) {
@@ -72,18 +93,19 @@
// Source photo will be displayed if there is no filter stacked.
Photo photo = source;
- int size = topFilterOutputted ? appliedStack.size() : appliedStack.size() - 1;
+ int size = outputTopFilter ? appliedStack.size() : appliedStack.size() - 1;
for (int i = 0; i < size && !paused; i++) {
photo = runFilter(i);
}
- photoView.setPhoto(photo, topFilterOutputted);
+ // Clear photo-view transformation when the top filter will be outputted.
+ photoView.setPhoto(photo, outputTopFilter);
}
}
private void invalidateTopFilter() {
if (!appliedStack.empty()) {
+ outputTopFilter = true;
photoView.setPhoto(runFilter(appliedStack.size() - 1), true);
- topFilterOutputted = true;
}
}
@@ -133,12 +155,12 @@
});
}
- public void saveBitmap(final OnDoneBitmapCallback callback) {
+ public void getOutputBitmap(final OnDoneBitmapCallback callback) {
photoView.queue(new Runnable() {
@Override
public void run() {
- int filterIndex = appliedStack.size() - (topFilterOutputted ? 1 : 2);
+ int filterIndex = appliedStack.size() - (outputTopFilter ? 1 : 2);
Photo photo = (filterIndex < 0) ? source : buffers[getOutBufferIndex(filterIndex)];
final Bitmap bitmap = (photo != null) ? photo.save() : null;
photoView.post(new Runnable() {
@@ -166,7 +188,7 @@
private void pushFilterInternal(Filter filter) {
appliedStack.push(filter);
- topFilterOutputted = false;
+ outputTopFilter = false;
stackChanged();
}
diff --git a/src/com/android/gallery3d/photoeditor/PhotoEditor.java b/src/com/android/gallery3d/photoeditor/PhotoEditor.java
index 2294d03..8f3990b 100644
--- a/src/com/android/gallery3d/photoeditor/PhotoEditor.java
+++ b/src/com/android/gallery3d/photoeditor/PhotoEditor.java
@@ -30,15 +30,19 @@
*/
public class PhotoEditor extends Activity {
+ private static final String SAVE_URI_KEY = "save_uri";
+
private Uri sourceUri;
private Uri saveUri;
private FilterStack filterStack;
private ActionBar actionBar;
+ private EffectsBar effectsBar;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.photoeditor_main);
+ SpinnerProgressDialog.initialize((ViewGroup) findViewById(R.id.toolbar));
Intent intent = getIntent();
if (Intent.ACTION_EDIT.equalsIgnoreCase(intent.getAction())) {
@@ -53,24 +57,26 @@
public void onStackChanged(boolean canUndo, boolean canRedo) {
actionBar.updateButtons(canUndo, canRedo);
}
- });
+ }, savedInstanceState);
+ if (savedInstanceState != null) {
+ saveUri = savedInstanceState.getParcelable(SAVE_URI_KEY);
+ actionBar.updateSave(saveUri == null);
+ }
- EffectsBar effectsBar = (EffectsBar) findViewById(R.id.effects_bar);
+ // Effects-bar is initially disabled until photo is successfully loaded.
+ effectsBar = (EffectsBar) findViewById(R.id.effects_bar);
effectsBar.initialize(filterStack);
+ effectsBar.setEnabled(false);
- actionBar.setClickRunnable(R.id.undo_button, createUndoRedoRunnable(true, effectsBar));
- actionBar.setClickRunnable(R.id.redo_button, createUndoRedoRunnable(false, effectsBar));
- actionBar.setClickRunnable(R.id.save_button, createSaveRunnable(effectsBar));
- actionBar.setClickRunnable(R.id.share_button, createShareRunnable(effectsBar));
- actionBar.setClickRunnable(R.id.action_bar_back, createBackRunnable(effectsBar));
- }
-
- private SpinnerProgressDialog createProgressDialog() {
- return SpinnerProgressDialog.show((ViewGroup) findViewById(R.id.toolbar));
+ actionBar.setClickRunnable(R.id.undo_button, createUndoRedoRunnable(true));
+ actionBar.setClickRunnable(R.id.redo_button, createUndoRedoRunnable(false));
+ actionBar.setClickRunnable(R.id.save_button, createSaveRunnable());
+ actionBar.setClickRunnable(R.id.share_button, createShareRunnable());
+ actionBar.setClickRunnable(R.id.action_bar_back, createBackRunnable());
}
private void openPhoto() {
- final SpinnerProgressDialog progressDialog = createProgressDialog();
+ SpinnerProgressDialog.showDialog();
LoadScreennailTask.Callback callback = new LoadScreennailTask.Callback() {
@Override
@@ -79,7 +85,8 @@
@Override
public void onDone() {
- progressDialog.dismiss();
+ SpinnerProgressDialog.dismissDialog();
+ effectsBar.setEnabled(result != null);
}
});
}
@@ -87,7 +94,7 @@
new LoadScreennailTask(this, callback).execute(sourceUri);
}
- private Runnable createUndoRedoRunnable(final boolean undo, final EffectsBar effectsBar) {
+ private Runnable createUndoRedoRunnable(final boolean undo) {
return new Runnable() {
@Override
@@ -96,12 +103,12 @@
@Override
public void run() {
- final SpinnerProgressDialog progressDialog = createProgressDialog();
+ SpinnerProgressDialog.showDialog();
OnDoneCallback callback = new OnDoneCallback() {
@Override
public void onDone() {
- progressDialog.dismiss();
+ SpinnerProgressDialog.dismissDialog();
}
};
if (undo) {
@@ -115,7 +122,7 @@
};
}
- private Runnable createSaveRunnable(final EffectsBar effectsBar) {
+ private Runnable createSaveRunnable() {
return new Runnable() {
@Override
@@ -124,8 +131,8 @@
@Override
public void run() {
- final SpinnerProgressDialog progressDialog = createProgressDialog();
- filterStack.saveBitmap(new OnDoneBitmapCallback() {
+ SpinnerProgressDialog.showDialog();
+ filterStack.getOutputBitmap(new OnDoneBitmapCallback() {
@Override
public void onDone(Bitmap bitmap) {
@@ -133,9 +140,9 @@
@Override
public void onComplete(Uri result) {
- progressDialog.dismiss();
- actionBar.updateSave(result == null);
+ SpinnerProgressDialog.dismissDialog();
saveUri = result;
+ actionBar.updateSave(saveUri == null);
}
};
new SaveCopyTask(PhotoEditor.this, sourceUri, callback).execute(
@@ -148,7 +155,7 @@
};
}
- private Runnable createShareRunnable(final EffectsBar effectsBar) {
+ private Runnable createShareRunnable() {
return new Runnable() {
@Override
@@ -169,7 +176,7 @@
};
}
- private Runnable createBackRunnable(final EffectsBar effectsBar) {
+ private Runnable createBackRunnable() {
return new Runnable() {
@Override
@@ -200,15 +207,23 @@
}
@Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ filterStack.saveStacks(outState);
+ outState.putParcelable(SAVE_URI_KEY, saveUri);
+ }
+
+ @Override
public void onBackPressed() {
actionBar.clickBack();
}
@Override
protected void onPause() {
- // TODO: Close running progress dialogs as all pending operations will be paused.
super.onPause();
filterStack.onPause();
+ // Dismiss any running progress dialog as all operations are paused.
+ SpinnerProgressDialog.dismissDialog();
}
@Override
diff --git a/src/com/android/gallery3d/photoeditor/SaveCopyTask.java b/src/com/android/gallery3d/photoeditor/SaveCopyTask.java
index bedd416..b7d5626 100644
--- a/src/com/android/gallery3d/photoeditor/SaveCopyTask.java
+++ b/src/com/android/gallery3d/photoeditor/SaveCopyTask.java
@@ -136,7 +136,7 @@
ContentValues values = new ContentValues();
values.put(Images.Media.TITLE, saveFileName);
- values.put(Images.Media.DISPLAY_NAME, saveFileName);
+ values.put(Images.Media.DISPLAY_NAME, file.getName());
values.put(Images.Media.MIME_TYPE, "image/jpeg");
values.put(Images.Media.DATE_TAKEN, dateTaken);
values.put(Images.Media.DATE_MODIFIED, now);
diff --git a/src/com/android/gallery3d/photoeditor/SpinnerProgressDialog.java b/src/com/android/gallery3d/photoeditor/SpinnerProgressDialog.java
index 9a3d849..065075e 100644
--- a/src/com/android/gallery3d/photoeditor/SpinnerProgressDialog.java
+++ b/src/com/android/gallery3d/photoeditor/SpinnerProgressDialog.java
@@ -18,55 +18,68 @@
import android.app.Dialog;
import android.view.MotionEvent;
+import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ProgressBar;
import com.android.gallery3d.R;
+import java.util.ArrayList;
+
/**
* Spinner model progress dialog that disables all tools for user interaction after it shows up and
- * and re-enables them after it dismisses.
+ * and re-enables them after it dismisses; this class along with all its methods should be accessed
+ * in only UI thread and allows only one instance at a time.
*/
public class SpinnerProgressDialog extends Dialog {
- private final ViewGroup tools;
+ private static ViewGroup toolbar;
+ private static SpinnerProgressDialog dialog;
+ private final ArrayList<View> enabledTools = new ArrayList<View>();
- public static SpinnerProgressDialog show(ViewGroup tools) {
- SpinnerProgressDialog dialog = new SpinnerProgressDialog(tools);
- dialog.setCancelable(false);
- dialog.show();
- return dialog;
+ public static void initialize(ViewGroup toolbar) {
+ SpinnerProgressDialog.toolbar = toolbar;
}
- private SpinnerProgressDialog(ViewGroup tools) {
- super(tools.getContext(), R.style.SpinnerProgressDialog);
+ public static void showDialog() {
+ // There should be only one progress dialog running at a time.
+ if (dialog == null) {
+ dialog = new SpinnerProgressDialog();
+ dialog.setCancelable(false);
+ dialog.show();
+ // Disable enabled tools when showing spinner progress dialog.
+ for (int i = 0; i < toolbar.getChildCount(); i++) {
+ View view = toolbar.getChildAt(i);
+ if (view.isEnabled()) {
+ dialog.enabledTools.add(view);
+ view.setEnabled(false);
+ }
+ }
+ }
+ }
- addContentView(new ProgressBar(tools.getContext()), new LayoutParams(
+ public static void dismissDialog() {
+ if (dialog != null) {
+ dialog.dismiss();
+ // Enable tools that were disabled by this spinner progress dialog.
+ for (View view : dialog.enabledTools) {
+ view.setEnabled(true);
+ }
+ dialog = null;
+ }
+ }
+
+ private SpinnerProgressDialog() {
+ super(toolbar.getContext(), R.style.SpinnerProgressDialog);
+ addContentView(new ProgressBar(toolbar.getContext()), new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
-
- this.tools = tools;
- enableTools(false);
- }
-
- @Override
- public void dismiss() {
- super.dismiss();
-
- enableTools(true);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
-
// Pass touch events to tools for killing idle even when the progress dialog is shown.
- return tools.dispatchTouchEvent(event);
- }
-
- private void enableTools(boolean enabled) {
- for (int i = 0; i < tools.getChildCount(); i++) {
- tools.getChildAt(i).setEnabled(enabled);
- }
+ return toolbar.dispatchTouchEvent(event);
}
}
diff --git a/src/com/android/gallery3d/photoeditor/actions/ColorTemperatureAction.java b/src/com/android/gallery3d/photoeditor/actions/ColorTemperatureAction.java
index 41a89db..24978fa 100644
--- a/src/com/android/gallery3d/photoeditor/actions/ColorTemperatureAction.java
+++ b/src/com/android/gallery3d/photoeditor/actions/ColorTemperatureAction.java
@@ -44,7 +44,7 @@
@Override
public void onProgressChanged(float progress, boolean fromUser) {
if (fromUser) {
- filter.setColorTemperature(progress);
+ filter.setScale(progress);
notifyFilterChanged(filter, true);
}
}
diff --git a/src/com/android/gallery3d/photoeditor/actions/Doodle.java b/src/com/android/gallery3d/photoeditor/actions/Doodle.java
new file mode 100644
index 0000000..ea23e23
--- /dev/null
+++ b/src/com/android/gallery3d/photoeditor/actions/Doodle.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2010 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.photoeditor.actions;
+
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Vector;
+
+/**
+ * Doodle that consists of a color and doodling path for drawing.
+ */
+public class Doodle implements Parcelable {
+
+ private final int color;
+ private final Path normalizedPath = new Path();
+ private final Vector<PointF> points = new Vector<PointF>();
+
+ /**
+ * Creates paint for doodles.
+ */
+ public static Paint createPaint() {
+ Paint paint = new Paint(Paint.DITHER_FLAG | Paint.ANTI_ALIAS_FLAG);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeJoin(Paint.Join.ROUND);
+ paint.setStrokeCap(Paint.Cap.ROUND);
+ paint.setStrokeWidth(15);
+ return paint;
+ }
+
+ public Doodle(int color, PointF startPoint) {
+ this.color = Color.argb(192, Color.red(color), Color.green(color), Color.blue(color));
+ normalizedPath.moveTo(startPoint.x, startPoint.y);
+ points.add(startPoint);
+ }
+
+ /**
+ * Adds control points whose coordinates range from 0 to 1 to construct the doodle path.
+ *
+ * @return true if the constructed path is in (0, 0, 1, 1) bounds; otherwise, false.
+ */
+ public boolean addControlPoint(PointF point) {
+ PointF last = points.lastElement();
+ normalizedPath.quadTo(last.x, last.y, (last.x + point.x) / 2, (last.y + point.y) / 2);
+ points.add(point);
+
+ RectF r = new RectF();
+ normalizedPath.computeBounds(r, false);
+ return r.intersects(0, 0, 1, 1);
+ }
+
+ public int getColor() {
+ return color;
+ }
+
+ public boolean isEmpty() {
+ return normalizedPath.isEmpty();
+ }
+
+ /**
+ * Gets the drawing path from the normalized doodle path.
+ */
+ public void getDrawingPath(Matrix matrix, Path path) {
+ path.set(normalizedPath);
+ path.transform(matrix);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(color);
+ dest.writeInt(points.size());
+ for (PointF point : points) {
+ dest.writeParcelable(point, 0);
+ }
+ }
+
+ public static final Parcelable.Creator<Doodle> CREATOR = new Parcelable.Creator<Doodle>() {
+
+ @Override
+ public Doodle createFromParcel(Parcel source) {
+ int color = source.readInt();
+ int size = source.readInt();
+ if (size > 0) {
+ Doodle doodle = new Doodle(color, (PointF) source.readParcelable(null));
+ for (int i = 1; i < size; i++) {
+ doodle.addControlPoint((PointF) source.readParcelable(null));
+ }
+ return doodle;
+ }
+ return new Doodle(color, new PointF(0, 0));
+ }
+
+ @Override
+ public Doodle[] newArray(int size) {
+ return new Doodle[size];
+ }};
+}
diff --git a/src/com/android/gallery3d/photoeditor/actions/DoodleAction.java b/src/com/android/gallery3d/photoeditor/actions/DoodleAction.java
index b82414d..4ad2cfb 100644
--- a/src/com/android/gallery3d/photoeditor/actions/DoodleAction.java
+++ b/src/com/android/gallery3d/photoeditor/actions/DoodleAction.java
@@ -17,7 +17,6 @@
package com.android.gallery3d.photoeditor.actions;
import android.content.Context;
-import android.graphics.Path;
import android.util.AttributeSet;
import com.android.gallery3d.photoeditor.filters.DoodleFilter;
@@ -64,8 +63,8 @@
}
@Override
- public void onDoodleFinished(Path path, int color) {
- filter.addPath(path, color);
+ public void onDoodleFinished(Doodle doodle) {
+ filter.addDoodle(doodle);
notifyFilterChanged(filter, false);
}
});
diff --git a/src/com/android/gallery3d/photoeditor/actions/DoodlePaint.java b/src/com/android/gallery3d/photoeditor/actions/DoodlePaint.java
deleted file mode 100644
index bcde9f1..0000000
--- a/src/com/android/gallery3d/photoeditor/actions/DoodlePaint.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2010 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.photoeditor.actions;
-
-import android.graphics.Paint;
-
-/**
- * A paint class for doodle effect.
- */
-public class DoodlePaint extends Paint {
-
- public DoodlePaint() {
- super(Paint.DITHER_FLAG | Paint.ANTI_ALIAS_FLAG);
-
- setStyle(Paint.Style.STROKE);
- setStrokeJoin(Paint.Join.ROUND);
- setStrokeCap(Paint.Cap.ROUND);
- setStrokeWidth(15);
- }
-}
diff --git a/src/com/android/gallery3d/photoeditor/actions/DoodleView.java b/src/com/android/gallery3d/photoeditor/actions/DoodleView.java
index cc5af84..b596861 100644
--- a/src/com/android/gallery3d/photoeditor/actions/DoodleView.java
+++ b/src/com/android/gallery3d/photoeditor/actions/DoodleView.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
@@ -40,19 +39,20 @@
void onDoodleInPhotoBounds();
- void onDoodleFinished(Path path, int color);
+ void onDoodleFinished(Doodle doodle);
}
- private final Path normalizedPath = new Path();
- private final Path drawingPath = new Path();
- private final Paint doodlePaint = new DoodlePaint();
private final Paint bitmapPaint = new Paint(Paint.DITHER_FLAG);
+ private final Paint doodlePaint = Doodle.createPaint();
private final PointF lastPoint = new PointF();
- private final Matrix pathMatrix = new Matrix();
+ private final Path drawingPath = new Path();
+ private final Matrix drawingMatrix = new Matrix();
private final Matrix displayMatrix = new Matrix();
private Bitmap bitmap;
private Canvas bitmapCanvas;
+ private Doodle doodle;
+ private int color;
private OnDoodleChangeListener listener;
public DoodleView(Context context, AttributeSet attrs) {
@@ -71,50 +71,51 @@
if ((bitmap == null) && !r.isEmpty()) {
bitmap = Bitmap.createBitmap((int) r.width(), (int) r.height(),
Bitmap.Config.ARGB_8888);
- bitmap.eraseColor(0x00000000);
bitmapCanvas = new Canvas(bitmap);
// Set up a matrix that maps back normalized paths to be drawn on the bitmap or canvas.
- pathMatrix.setRectToRect(new RectF(0, 0, 1, 1), r, Matrix.ScaleToFit.FILL);
+ drawingMatrix.setRectToRect(new RectF(0, 0, 1, 1), r, Matrix.ScaleToFit.FILL);
}
displayMatrix.setRectToRect(r, displayBounds, Matrix.ScaleToFit.FILL);
}
private void drawDoodle(Canvas canvas) {
- if ((canvas != null) && !normalizedPath.isEmpty()) {
- drawingPath.set(normalizedPath);
- drawingPath.transform(pathMatrix);
+ if ((canvas != null) && (doodle != null)) {
+ doodlePaint.setColor(doodle.getColor());
+ doodle.getDrawingPath(drawingMatrix, drawingPath);
canvas.drawPath(drawingPath, doodlePaint);
}
}
public void setColor(int color) {
- // Reset path to draw in a new color.
- finishCurrentPath();
- normalizedPath.moveTo(lastPoint.x, lastPoint.y);
- doodlePaint.setColor(Color.argb(192, Color.red(color), Color.green(color),
- Color.blue(color)));
+ // Restart doodle to draw in a new color.
+ this.color = color;
+ finishDoodle();
+ startDoodle();
}
- private void finishCurrentPath() {
- if (!normalizedPath.isEmpty()) {
- // Update the finished path to the bitmap.
+ private void startDoodle() {
+ doodle = new Doodle(color, new PointF(lastPoint.x, lastPoint.y));
+ }
+
+ private void finishDoodle() {
+ if ((doodle != null) && !doodle.isEmpty()) {
+ // Update the finished non-empty doodle to the bitmap.
drawDoodle(bitmapCanvas);
if (listener != null) {
- listener.onDoodleFinished(new Path(normalizedPath), doodlePaint.getColor());
+ listener.onDoodleFinished(doodle);
}
- normalizedPath.rewind();
invalidate();
}
+ doodle = null;
}
- private void checkCurrentPathInBounds() {
- if ((listener != null) && !normalizedPath.isEmpty()) {
- RectF r = new RectF();
- normalizedPath.computeBounds(r, false);
- if (r.intersects(0, 0, 1, 1)) {
+ private void addLastPointIntoDoodle() {
+ if ((doodle != null) && doodle.addControlPoint(new PointF(lastPoint.x, lastPoint.y))) {
+ if (listener != null) {
listener.onDoodleInPhotoBounds();
}
+ invalidate();
}
}
@@ -129,26 +130,20 @@
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mapPhotoPoint(x, y, lastPoint);
- normalizedPath.moveTo(lastPoint.x, lastPoint.y);
+ startDoodle();
break;
case MotionEvent.ACTION_MOVE:
- float lastX = lastPoint.x;
- float lastY = lastPoint.y;
mapPhotoPoint(x, y, lastPoint);
- normalizedPath.quadTo(lastX, lastY, (lastX + lastPoint.x) / 2,
- (lastY + lastPoint.y) / 2);
- checkCurrentPathInBounds();
- invalidate();
+ addLastPointIntoDoodle();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
// Line to last position with offset to draw at least dots for single clicks.
mapPhotoPoint(x + 1, y + 1, lastPoint);
- normalizedPath.lineTo(lastPoint.x, lastPoint.y);
- checkCurrentPathInBounds();
- finishCurrentPath();
+ addLastPointIntoDoodle();
+ finishDoodle();
break;
}
}
diff --git a/src/com/android/gallery3d/photoeditor/actions/FaceTanAction.java b/src/com/android/gallery3d/photoeditor/actions/FaceTanAction.java
new file mode 100644
index 0000000..a82f330
--- /dev/null
+++ b/src/com/android/gallery3d/photoeditor/actions/FaceTanAction.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 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.photoeditor.actions;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.gallery3d.photoeditor.filters.FaceTanFilter;
+
+/**
+ * An action handling face tanning effect.
+ */
+public class FaceTanAction extends EffectAction {
+
+ private static final float DEFAULT_SCALE = 0.5f;
+
+ private ScaleSeekBar scalePicker;
+
+ public FaceTanAction(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void doBegin() {
+ final FaceTanFilter filter = new FaceTanFilter();
+
+ scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.GENERIC);
+ scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
+
+ @Override
+ public void onProgressChanged(float progress, boolean fromUser) {
+ if (fromUser) {
+ filter.setScale(progress);
+ notifyFilterChanged(filter, true);
+ }
+ }
+ });
+ scalePicker.setProgress(DEFAULT_SCALE);
+
+ filter.setScale(DEFAULT_SCALE);
+ notifyFilterChanged(filter, true);
+ }
+
+ @Override
+ public void doEnd() {
+ scalePicker.setOnScaleChangeListener(null);
+ }
+}
diff --git a/src/com/android/gallery3d/photoeditor/actions/FillLightAction.java b/src/com/android/gallery3d/photoeditor/actions/FillLightAction.java
index 962486b..73cf3d8 100644
--- a/src/com/android/gallery3d/photoeditor/actions/FillLightAction.java
+++ b/src/com/android/gallery3d/photoeditor/actions/FillLightAction.java
@@ -44,7 +44,7 @@
@Override
public void onProgressChanged(float progress, boolean fromUser) {
if (fromUser) {
- filter.setBacklight(progress);
+ filter.setScale(progress);
notifyFilterChanged(filter, true);
}
}
diff --git a/src/com/android/gallery3d/photoeditor/actions/HighlightAction.java b/src/com/android/gallery3d/photoeditor/actions/HighlightAction.java
index cd8f4b2..a3d62d2 100644
--- a/src/com/android/gallery3d/photoeditor/actions/HighlightAction.java
+++ b/src/com/android/gallery3d/photoeditor/actions/HighlightAction.java
@@ -44,7 +44,7 @@
@Override
public void onProgressChanged(float progress, boolean fromUser) {
if (fromUser) {
- filter.setHighlight(progress);
+ filter.setScale(progress);
notifyFilterChanged(filter, true);
}
}
diff --git a/src/com/android/gallery3d/photoeditor/actions/SaturationAction.java b/src/com/android/gallery3d/photoeditor/actions/SaturationAction.java
index 31bcfd6..2f67e0a 100644
--- a/src/com/android/gallery3d/photoeditor/actions/SaturationAction.java
+++ b/src/com/android/gallery3d/photoeditor/actions/SaturationAction.java
@@ -44,7 +44,7 @@
@Override
public void onProgressChanged(float progress, boolean fromUser) {
if (fromUser) {
- filter.setSaturation(progress);
+ filter.setScale(progress);
notifyFilterChanged(filter, true);
}
}
diff --git a/src/com/android/gallery3d/photoeditor/actions/ShadowAction.java b/src/com/android/gallery3d/photoeditor/actions/ShadowAction.java
index 185febc..15ba850 100644
--- a/src/com/android/gallery3d/photoeditor/actions/ShadowAction.java
+++ b/src/com/android/gallery3d/photoeditor/actions/ShadowAction.java
@@ -44,7 +44,7 @@
@Override
public void onProgressChanged(float progress, boolean fromUser) {
if (fromUser) {
- filter.setShadow(progress);
+ filter.setScale(progress);
notifyFilterChanged(filter, true);
}
}
diff --git a/src/com/android/gallery3d/photoeditor/actions/SharpenAction.java b/src/com/android/gallery3d/photoeditor/actions/SharpenAction.java
index 7524c76..c6b240b 100644
--- a/src/com/android/gallery3d/photoeditor/actions/SharpenAction.java
+++ b/src/com/android/gallery3d/photoeditor/actions/SharpenAction.java
@@ -44,14 +44,14 @@
@Override
public void onProgressChanged(float progress, boolean fromUser) {
if (fromUser) {
- filter.setSharpen(progress);
+ filter.setScale(progress);
notifyFilterChanged(filter, true);
}
}
});
scalePicker.setProgress(DEFAULT_SCALE);
- filter.setSharpen(DEFAULT_SCALE);
+ filter.setScale(DEFAULT_SCALE);
notifyFilterChanged(filter, true);
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/AbstractScaleFilter.java b/src/com/android/gallery3d/photoeditor/filters/AbstractScaleFilter.java
new file mode 100644
index 0000000..727a98c
--- /dev/null
+++ b/src/com/android/gallery3d/photoeditor/filters/AbstractScaleFilter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 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.photoeditor.filters;
+
+import android.os.Parcel;
+
+/**
+ * Filter base that has a scale value ranging from 0 to 1 for adjustments and can persist states.
+ */
+public abstract class AbstractScaleFilter extends Filter {
+
+ protected float scale;
+
+ /**
+ * Sets the scale from 0 to 1.
+ */
+ public void setScale(float scale) {
+ this.scale = scale;
+ validate();
+ }
+
+ @Override
+ protected void writeToParcel(Parcel out) {
+ out.writeFloat(scale);
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ scale = in.readFloat();
+ }
+}
diff --git a/src/com/android/gallery3d/photoeditor/filters/AutoFixFilter.java b/src/com/android/gallery3d/photoeditor/filters/AutoFixFilter.java
index 78153d0..d168a78 100644
--- a/src/com/android/gallery3d/photoeditor/filters/AutoFixFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/AutoFixFilter.java
@@ -24,19 +24,9 @@
/**
* Auto-fix filter applied to the image.
*/
-public class AutoFixFilter extends Filter {
+public class AutoFixFilter extends AbstractScaleFilter {
- private float scale;
-
- /**
- * Sets the auto-fix level.
- *
- * @param scale ranges from 0 to 1.
- */
- public void setScale(float scale) {
- this.scale = scale;
- validate();
- }
+ public static final Creator<AutoFixFilter> CREATOR = creatorOf(AutoFixFilter.class);
@Override
public void process(Photo src, Photo dst) {
diff --git a/src/com/android/gallery3d/photoeditor/filters/ColorTemperatureFilter.java b/src/com/android/gallery3d/photoeditor/filters/ColorTemperatureFilter.java
index f9c6400..c5a6a35 100644
--- a/src/com/android/gallery3d/photoeditor/filters/ColorTemperatureFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/ColorTemperatureFilter.java
@@ -24,19 +24,10 @@
/**
* Color temperature filter applied to the image.
*/
-public class ColorTemperatureFilter extends Filter {
+public class ColorTemperatureFilter extends AbstractScaleFilter {
- private float scale;
-
- /**
- * Sets the color temperature level.
- *
- * @param scale ranges from 0 to 1.
- */
- public void setColorTemperature(float scale) {
- this.scale = scale;
- validate();
- }
+ public static final Creator<ColorTemperatureFilter> CREATOR = creatorOf(
+ ColorTemperatureFilter.class);
@Override
public void process(Photo src, Photo dst) {
diff --git a/src/com/android/gallery3d/photoeditor/filters/CropFilter.java b/src/com/android/gallery3d/photoeditor/filters/CropFilter.java
index f984f3b..ccca813 100644
--- a/src/com/android/gallery3d/photoeditor/filters/CropFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/CropFilter.java
@@ -19,6 +19,7 @@
import android.graphics.RectF;
import android.media.effect.Effect;
import android.media.effect.EffectFactory;
+import android.os.Parcel;
import com.android.gallery3d.photoeditor.Photo;
@@ -27,6 +28,8 @@
*/
public class CropFilter extends Filter {
+ public static final Creator<CropFilter> CREATOR = creatorOf(CropFilter.class);
+
private RectF bounds;
/**
@@ -49,4 +52,14 @@
effect.setParameter("height", dst.height());
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
+
+ @Override
+ protected void writeToParcel(Parcel out) {
+ out.writeParcelable(bounds, 0);
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ bounds = in.readParcelable(null);
+ }
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/CrossProcessFilter.java b/src/com/android/gallery3d/photoeditor/filters/CrossProcessFilter.java
index bea8a27..e82a667 100644
--- a/src/com/android/gallery3d/photoeditor/filters/CrossProcessFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/CrossProcessFilter.java
@@ -25,6 +25,8 @@
*/
public class CrossProcessFilter extends Filter {
+ public static final Creator<CrossProcessFilter> CREATOR = creatorOf(CrossProcessFilter.class);
+
public CrossProcessFilter() {
validate();
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/DocumentaryFilter.java b/src/com/android/gallery3d/photoeditor/filters/DocumentaryFilter.java
index 4075b27..d6f347b 100644
--- a/src/com/android/gallery3d/photoeditor/filters/DocumentaryFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/DocumentaryFilter.java
@@ -25,6 +25,8 @@
*/
public class DocumentaryFilter extends Filter {
+ public static final Creator<DocumentaryFilter> CREATOR = creatorOf(DocumentaryFilter.class);
+
public DocumentaryFilter() {
validate();
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/DoodleFilter.java b/src/com/android/gallery3d/photoeditor/filters/DoodleFilter.java
index d9e904a..277e06d 100644
--- a/src/com/android/gallery3d/photoeditor/filters/DoodleFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/DoodleFilter.java
@@ -24,9 +24,10 @@
import android.graphics.RectF;
import android.media.effect.Effect;
import android.media.effect.EffectFactory;
+import android.os.Parcel;
import com.android.gallery3d.photoeditor.Photo;
-import com.android.gallery3d.photoeditor.actions.DoodlePaint;
+import com.android.gallery3d.photoeditor.actions.Doodle;
import java.util.Vector;
@@ -35,17 +36,9 @@
*/
public class DoodleFilter extends Filter {
- private static class ColorPath {
- private final int color;
- private final Path path;
+ public static final Creator<DoodleFilter> CREATOR = creatorOf(DoodleFilter.class);
- ColorPath(int color, Path path) {
- this.color = color;
- this.path = path;
- }
- }
-
- private final Vector<ColorPath> doodles = new Vector<ColorPath>();
+ private final Vector<Doodle> doodles = new Vector<Doodle>();
/**
* Signals once at least a doodle drawn within photo bounds; this filter is regarded as invalid
@@ -55,11 +48,8 @@
validate();
}
- /**
- * The path coordinates used here should range from 0 to 1.
- */
- public void addPath(Path path, int color) {
- doodles.add(new ColorPath(color, path));
+ public void addDoodle(Doodle doodle) {
+ doodles.add(doodle);
}
@Override
@@ -72,11 +62,10 @@
new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), Matrix.ScaleToFit.FILL);
Path drawingPath = new Path();
- Paint paint = new DoodlePaint();
- for (ColorPath doodle : doodles) {
- paint.setColor(doodle.color);
- drawingPath.set(doodle.path);
- drawingPath.transform(matrix);
+ Paint paint = Doodle.createPaint();
+ for (Doodle doodle : doodles) {
+ paint.setColor(doodle.getColor());
+ doodle.getDrawingPath(matrix, drawingPath);
canvas.drawPath(drawingPath, paint);
}
@@ -84,4 +73,20 @@
effect.setParameter("bitmap", bitmap);
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
+
+ @Override
+ protected void writeToParcel(Parcel out) {
+ out.writeInt(doodles.size());
+ for (Doodle doodle : doodles) {
+ out.writeParcelable(doodle, 0);
+ }
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ int size = in.readInt();
+ for (int i = 0; i < size; i++) {
+ doodles.add((Doodle) in.readParcelable(Doodle.class.getClassLoader()));
+ }
+ }
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/DuotoneFilter.java b/src/com/android/gallery3d/photoeditor/filters/DuotoneFilter.java
index 89e95b9..b94f95e 100644
--- a/src/com/android/gallery3d/photoeditor/filters/DuotoneFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/DuotoneFilter.java
@@ -18,6 +18,7 @@
import android.media.effect.Effect;
import android.media.effect.EffectFactory;
+import android.os.Parcel;
import com.android.gallery3d.photoeditor.Photo;
@@ -26,6 +27,8 @@
*/
public class DuotoneFilter extends Filter {
+ public static final Creator<DuotoneFilter> CREATOR = creatorOf(DuotoneFilter.class);
+
private int firstColor;
private int secondColor;
@@ -42,4 +45,16 @@
effect.setParameter("second_color", secondColor);
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
+
+ @Override
+ protected void writeToParcel(Parcel out) {
+ out.writeInt(firstColor);
+ out.writeInt(secondColor);
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ firstColor = in.readInt();
+ secondColor = in.readInt();
+ }
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/FaceTanFilter.java b/src/com/android/gallery3d/photoeditor/filters/FaceTanFilter.java
new file mode 100644
index 0000000..c52bb88
--- /dev/null
+++ b/src/com/android/gallery3d/photoeditor/filters/FaceTanFilter.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 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.photoeditor.filters;
+
+import android.media.effect.Effect;
+
+import com.android.gallery3d.photoeditor.Photo;
+
+/**
+ * Face tanning filter applied to the image.
+ */
+public class FaceTanFilter extends AbstractScaleFilter {
+
+ public static final Creator<FaceTanFilter> CREATOR = creatorOf(FaceTanFilter.class);
+
+ @Override
+ public void process(Photo src, Photo dst) {
+ Effect effect = getEffect("com.google.android.media.effect.effects.FaceTanningEffect");
+ effect.setParameter("blend", scale);
+ effect.apply(src.texture(), src.width(), src.height(), dst.texture());
+ }
+}
diff --git a/src/com/android/gallery3d/photoeditor/filters/FaceliftFilter.java b/src/com/android/gallery3d/photoeditor/filters/FaceliftFilter.java
index 3c7a731..c6ad84b 100644
--- a/src/com/android/gallery3d/photoeditor/filters/FaceliftFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/FaceliftFilter.java
@@ -23,19 +23,9 @@
/**
* Facelift filter applied to the image.
*/
-public class FaceliftFilter extends Filter {
+public class FaceliftFilter extends AbstractScaleFilter {
- private float scale;
-
- /**
- * Sets the facelift level.
- *
- * @param scale ranges from 0 to 1.
- */
- public void setScale(float scale) {
- this.scale = scale;
- validate();
- }
+ public static final Creator<FaceliftFilter> CREATOR = creatorOf(FaceliftFilter.class);
@Override
public void process(Photo src, Photo dst) {
diff --git a/src/com/android/gallery3d/photoeditor/filters/FillLightFilter.java b/src/com/android/gallery3d/photoeditor/filters/FillLightFilter.java
index 2346953..3aedd74 100644
--- a/src/com/android/gallery3d/photoeditor/filters/FillLightFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/FillLightFilter.java
@@ -24,24 +24,14 @@
/**
* Fill-light filter applied to the image.
*/
-public class FillLightFilter extends Filter {
+public class FillLightFilter extends AbstractScaleFilter {
- private float backlight;
-
- /**
- * Sets the backlight level.
- *
- * @param backlight ranges from 0 to 1.
- */
- public void setBacklight(float backlight) {
- this.backlight = backlight;
- validate();
- }
+ public static final Creator<FillLightFilter> CREATOR = creatorOf(FillLightFilter.class);
@Override
public void process(Photo src, Photo dst) {
Effect effect = getEffect(EffectFactory.EFFECT_FILLLIGHT);
- effect.setParameter("strength", backlight);
+ effect.setParameter("strength", scale);
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/Filter.java b/src/com/android/gallery3d/photoeditor/filters/Filter.java
index 8c00dbb..baa3747 100644
--- a/src/com/android/gallery3d/photoeditor/filters/Filter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/Filter.java
@@ -18,6 +18,8 @@
import android.media.effect.Effect;
import android.media.effect.EffectContext;
+import android.os.Parcel;
+import android.os.Parcelable;
import com.android.gallery3d.photoeditor.Photo;
@@ -27,7 +29,7 @@
* Image filter for photo editing; most of its methods must be called from a single GL thread except
* validate()/isValid() that are called from UI thread.
*/
-public abstract class Filter {
+public abstract class Filter implements Parcelable {
// TODO: This should be set in MFF instead.
private static final int DEFAULT_TILE_SIZE = 640;
@@ -91,4 +93,33 @@
* @param dst destination photo having the same dimension as source photo as the output.
*/
public abstract void process(Photo src, Photo dst);
+
+ /**
+ * Instantiates CREATOR of subclasses for Parcelable implementations.
+ */
+ protected static <T extends Filter> Parcelable.Creator<T> creatorOf(Class<T> filterClass) {
+ return new FilterCreator<T>(filterClass);
+ }
+
+ /**
+ * Saves states for restoring filter later; subclasses can override this to persist states.
+ */
+ protected void writeToParcel(Parcel out) {
+ }
+
+ /**
+ * Restores filter from the saved states; subclasses can override this to persist states.
+ */
+ protected void readFromParcel(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ writeToParcel(dest);
+ }
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/FilterCreator.java b/src/com/android/gallery3d/photoeditor/filters/FilterCreator.java
new file mode 100644
index 0000000..9b05244
--- /dev/null
+++ b/src/com/android/gallery3d/photoeditor/filters/FilterCreator.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 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.photoeditor.filters;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.reflect.Array;
+
+/**
+ * Creator that creates the specific parcelable filter from the parcel.
+ */
+public class FilterCreator<T extends Filter> implements Parcelable.Creator<T> {
+
+ private final Class<T> filterClass;
+
+ public FilterCreator(Class<T> filterClass) {
+ this.filterClass = filterClass;
+ }
+
+ @Override
+ public T createFromParcel(Parcel source) {
+ try {
+ T filter = filterClass.newInstance();
+ filter.readFromParcel(source);
+ return filter;
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public T[] newArray(int size) {
+ return (T[]) Array.newInstance(filterClass, size);
+ }
+}
diff --git a/src/com/android/gallery3d/photoeditor/filters/FisheyeFilter.java b/src/com/android/gallery3d/photoeditor/filters/FisheyeFilter.java
index 6bd406c..7fe6108 100644
--- a/src/com/android/gallery3d/photoeditor/filters/FisheyeFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/FisheyeFilter.java
@@ -24,19 +24,9 @@
/**
* Fisheye filter applied to the image.
*/
-public class FisheyeFilter extends Filter {
+public class FisheyeFilter extends AbstractScaleFilter {
- private float scale;
-
- /**
- * Sets the fisheye distortion level.
- *
- * @param scale ranges from 0 to 1.
- */
- public void setScale(float scale) {
- this.scale = scale;
- validate();
- }
+ public static final Creator<FisheyeFilter> CREATOR = creatorOf(FisheyeFilter.class);
@Override
public void process(Photo src, Photo dst) {
diff --git a/src/com/android/gallery3d/photoeditor/filters/FlipFilter.java b/src/com/android/gallery3d/photoeditor/filters/FlipFilter.java
index 7035912..816aad8 100644
--- a/src/com/android/gallery3d/photoeditor/filters/FlipFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/FlipFilter.java
@@ -18,6 +18,7 @@
import android.media.effect.Effect;
import android.media.effect.EffectFactory;
+import android.os.Parcel;
import com.android.gallery3d.photoeditor.Photo;
@@ -26,20 +27,31 @@
*/
public class FlipFilter extends Filter {
- private boolean flipHorizontal;
- private boolean flipVertical;
+ public static final Creator<FlipFilter> CREATOR = creatorOf(FlipFilter.class);
+
+ private final boolean[] flips = new boolean[2];
public void setFlip(boolean flipHorizontal, boolean flipVertical) {
- this.flipHorizontal = flipHorizontal;
- this.flipVertical = flipVertical;
+ flips[0] = flipHorizontal;
+ flips[1] = flipVertical;
validate();
}
@Override
public void process(Photo src, Photo dst) {
Effect effect = getEffect(EffectFactory.EFFECT_FLIP);
- effect.setParameter("horizontal", flipHorizontal);
- effect.setParameter("vertical", flipVertical);
+ effect.setParameter("horizontal", flips[0]);
+ effect.setParameter("vertical", flips[1]);
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
+
+ @Override
+ protected void writeToParcel(Parcel out) {
+ out.writeBooleanArray(flips);
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ in.readBooleanArray(flips);
+ }
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/GrainFilter.java b/src/com/android/gallery3d/photoeditor/filters/GrainFilter.java
index ddaad7a..04867c6 100644
--- a/src/com/android/gallery3d/photoeditor/filters/GrainFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/GrainFilter.java
@@ -24,19 +24,9 @@
/**
* Film grain filter applied to the image.
*/
-public class GrainFilter extends Filter {
+public class GrainFilter extends AbstractScaleFilter {
- private float scale;
-
- /**
- * Set the grain noise level.
- *
- * @param scale ranges from 0 to 1.
- */
- public void setScale(float scale) {
- this.scale = scale;
- validate();
- }
+ public static final Creator<GrainFilter> CREATOR = creatorOf(GrainFilter.class);
@Override
public void process(Photo src, Photo dst) {
diff --git a/src/com/android/gallery3d/photoeditor/filters/GrayscaleFilter.java b/src/com/android/gallery3d/photoeditor/filters/GrayscaleFilter.java
index d5ef8a0..38dfb52 100644
--- a/src/com/android/gallery3d/photoeditor/filters/GrayscaleFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/GrayscaleFilter.java
@@ -25,6 +25,8 @@
*/
public class GrayscaleFilter extends Filter {
+ public static final Creator<GrayscaleFilter> CREATOR = creatorOf(GrayscaleFilter.class);
+
public GrayscaleFilter() {
validate();
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/HighlightFilter.java b/src/com/android/gallery3d/photoeditor/filters/HighlightFilter.java
index dfaaa65..e079c2e 100644
--- a/src/com/android/gallery3d/photoeditor/filters/HighlightFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/HighlightFilter.java
@@ -24,25 +24,15 @@
/**
* Highlight filter applied to the image.
*/
-public class HighlightFilter extends Filter {
+public class HighlightFilter extends AbstractScaleFilter {
- private float white;
-
- /**
- * Sets the highlight level.
- *
- * @param highlight ranges from 0 to 1.
- */
- public void setHighlight(float highlight) {
- white = 1f - highlight * 0.5f;
- validate();
- }
+ public static final Creator<HighlightFilter> CREATOR = creatorOf(HighlightFilter.class);
@Override
public void process(Photo src, Photo dst) {
Effect effect = getEffect(EffectFactory.EFFECT_BLACKWHITE);
effect.setParameter("black", 0f);
- effect.setParameter("white", white);
+ effect.setParameter("white", 1f - scale * 0.5f);
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/LomoishFilter.java b/src/com/android/gallery3d/photoeditor/filters/LomoishFilter.java
index 140f2d6..f8c5173 100644
--- a/src/com/android/gallery3d/photoeditor/filters/LomoishFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/LomoishFilter.java
@@ -25,6 +25,8 @@
*/
public class LomoishFilter extends Filter {
+ public static final Creator<LomoishFilter> CREATOR = creatorOf(LomoishFilter.class);
+
public LomoishFilter() {
validate();
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/NegativeFilter.java b/src/com/android/gallery3d/photoeditor/filters/NegativeFilter.java
index 94bf87e..88bbd58 100644
--- a/src/com/android/gallery3d/photoeditor/filters/NegativeFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/NegativeFilter.java
@@ -25,6 +25,8 @@
*/
public class NegativeFilter extends Filter {
+ public static final Creator<NegativeFilter> CREATOR = creatorOf(NegativeFilter.class);
+
public NegativeFilter() {
validate();
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/PosterizeFilter.java b/src/com/android/gallery3d/photoeditor/filters/PosterizeFilter.java
index 96f5985..186baa9 100644
--- a/src/com/android/gallery3d/photoeditor/filters/PosterizeFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/PosterizeFilter.java
@@ -25,6 +25,8 @@
*/
public class PosterizeFilter extends Filter {
+ public static final Creator<PosterizeFilter> CREATOR = creatorOf(PosterizeFilter.class);
+
public PosterizeFilter() {
validate();
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/RedEyeFilter.java b/src/com/android/gallery3d/photoeditor/filters/RedEyeFilter.java
index b499154..257d322 100644
--- a/src/com/android/gallery3d/photoeditor/filters/RedEyeFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/RedEyeFilter.java
@@ -19,6 +19,7 @@
import android.graphics.PointF;
import android.media.effect.Effect;
import android.media.effect.EffectFactory;
+import android.os.Parcel;
import com.android.gallery3d.photoeditor.Photo;
@@ -29,6 +30,8 @@
*/
public class RedEyeFilter extends Filter {
+ public static final Creator<RedEyeFilter> CREATOR = creatorOf(RedEyeFilter.class);
+
private final Vector<PointF> redeyes = new Vector<PointF>();
/**
@@ -51,4 +54,20 @@
effect.setParameter("centers", centers);
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
+
+ @Override
+ protected void writeToParcel(Parcel out) {
+ out.writeInt(redeyes.size());
+ for (PointF eye : redeyes) {
+ out.writeParcelable(eye, 0);
+ }
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ int size = in.readInt();
+ for (int i = 0; i < size; i++) {
+ redeyes.add((PointF) in.readParcelable(null));
+ }
+ }
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/RotateFilter.java b/src/com/android/gallery3d/photoeditor/filters/RotateFilter.java
index 548cc59..d377f96 100644
--- a/src/com/android/gallery3d/photoeditor/filters/RotateFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/RotateFilter.java
@@ -18,6 +18,7 @@
import android.media.effect.Effect;
import android.media.effect.EffectFactory;
+import android.os.Parcel;
import com.android.gallery3d.photoeditor.Photo;
@@ -26,6 +27,8 @@
*/
public class RotateFilter extends Filter {
+ public static final Creator<RotateFilter> CREATOR = creatorOf(RotateFilter.class);
+
private float degrees;
public void setAngle(float degrees) {
@@ -42,4 +45,14 @@
effect.setParameter("angle", (int) degrees);
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
+
+ @Override
+ protected void writeToParcel(Parcel out) {
+ out.writeFloat(degrees);
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ degrees = in.readFloat();
+ }
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/SaturationFilter.java b/src/com/android/gallery3d/photoeditor/filters/SaturationFilter.java
index b2c7cce..af08a7b 100644
--- a/src/com/android/gallery3d/photoeditor/filters/SaturationFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/SaturationFilter.java
@@ -24,24 +24,14 @@
/**
* Saturation filter applied to the image.
*/
-public class SaturationFilter extends Filter {
+public class SaturationFilter extends AbstractScaleFilter {
- private float scale;
-
- /**
- * Sets the saturation level.
- *
- * @param scale ranges from 0 to 1.
- */
- public void setSaturation(float scale) {
- this.scale = (scale - 0.5f) * 2;
- validate();
- }
+ public static final Creator<SaturationFilter> CREATOR = creatorOf(SaturationFilter.class);
@Override
public void process(Photo src, Photo dst) {
Effect effect = getEffect(EffectFactory.EFFECT_SATURATE);
- effect.setParameter("scale", scale);
+ effect.setParameter("scale", (scale - 0.5f) * 2);
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/SepiaFilter.java b/src/com/android/gallery3d/photoeditor/filters/SepiaFilter.java
index 170b95d..6c1a70e 100644
--- a/src/com/android/gallery3d/photoeditor/filters/SepiaFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/SepiaFilter.java
@@ -25,6 +25,8 @@
*/
public class SepiaFilter extends Filter {
+ public static final Creator<SepiaFilter> CREATOR = creatorOf(SepiaFilter.class);
+
public SepiaFilter() {
validate();
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/ShadowFilter.java b/src/com/android/gallery3d/photoeditor/filters/ShadowFilter.java
index 7931874..03960e4 100644
--- a/src/com/android/gallery3d/photoeditor/filters/ShadowFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/ShadowFilter.java
@@ -24,24 +24,14 @@
/**
* Shadow filter applied to the image.
*/
-public class ShadowFilter extends Filter {
+public class ShadowFilter extends AbstractScaleFilter {
- private float black;
-
- /**
- * Sets the shadow blackness level.
- *
- * @param shadow ranges from 0 to 1.
- */
- public void setShadow(float shadow) {
- black = shadow * 0.5f;
- validate();
- }
+ public static final Creator<ShadowFilter> CREATOR = creatorOf(ShadowFilter.class);
@Override
public void process(Photo src, Photo dst) {
Effect effect = getEffect(EffectFactory.EFFECT_BLACKWHITE);
- effect.setParameter("black", black);
+ effect.setParameter("black", scale * 0.5f);
effect.setParameter("white", 1f);
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/SharpenFilter.java b/src/com/android/gallery3d/photoeditor/filters/SharpenFilter.java
index e6f7cd5..f066dcf 100644
--- a/src/com/android/gallery3d/photoeditor/filters/SharpenFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/SharpenFilter.java
@@ -24,19 +24,9 @@
/**
* Sharpen filter applied to the image.
*/
-public class SharpenFilter extends Filter {
+public class SharpenFilter extends AbstractScaleFilter {
- private float scale;
-
- /**
- * Sets the sharpen level.
- *
- * @param scale ranges from 0 to 1.
- */
- public void setSharpen(float scale) {
- this.scale = scale;
- validate();
- }
+ public static final Creator<SharpenFilter> CREATOR = creatorOf(SharpenFilter.class);
@Override
public void process(Photo src, Photo dst) {
diff --git a/src/com/android/gallery3d/photoeditor/filters/StraightenFilter.java b/src/com/android/gallery3d/photoeditor/filters/StraightenFilter.java
index 30a8ac5..90738f0 100644
--- a/src/com/android/gallery3d/photoeditor/filters/StraightenFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/StraightenFilter.java
@@ -18,6 +18,7 @@
import android.media.effect.Effect;
import android.media.effect.EffectFactory;
+import android.os.Parcel;
import com.android.gallery3d.photoeditor.Photo;
@@ -26,12 +27,13 @@
*/
public class StraightenFilter extends Filter {
+ public static final Creator<StraightenFilter> CREATOR = creatorOf(StraightenFilter.class);
public static final float MAX_DEGREES = 30.0f;
- private float angle;
+ private float degrees;
public void setAngle(float degrees) {
- angle = -degrees;
+ this.degrees = degrees;
validate();
}
@@ -39,7 +41,17 @@
public void process(Photo src, Photo dst) {
Effect effect = getEffect(EffectFactory.EFFECT_STRAIGHTEN);
effect.setParameter("maxAngle", MAX_DEGREES);
- effect.setParameter("angle", angle);
+ effect.setParameter("angle", -degrees);
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
+
+ @Override
+ protected void writeToParcel(Parcel out) {
+ out.writeFloat(degrees);
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ degrees = in.readFloat();
+ }
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/TintFilter.java b/src/com/android/gallery3d/photoeditor/filters/TintFilter.java
index e5e467b..af3d777 100644
--- a/src/com/android/gallery3d/photoeditor/filters/TintFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/TintFilter.java
@@ -18,6 +18,7 @@
import android.media.effect.Effect;
import android.media.effect.EffectFactory;
+import android.os.Parcel;
import com.android.gallery3d.photoeditor.Photo;
@@ -26,17 +27,29 @@
*/
public class TintFilter extends Filter {
- private int tint;
+ public static final Creator<TintFilter> CREATOR = creatorOf(TintFilter.class);
+
+ private int color;
public void setTint(int color) {
- tint = color;
+ this.color = color;
validate();
}
@Override
public void process(Photo src, Photo dst) {
Effect effect = getEffect(EffectFactory.EFFECT_TINT);
- effect.setParameter("tint", tint);
+ effect.setParameter("tint", color);
effect.apply(src.texture(), src.width(), src.height(), dst.texture());
}
+
+ @Override
+ protected void writeToParcel(Parcel out) {
+ out.writeInt(color);
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ color = in.readInt();
+ }
}
diff --git a/src/com/android/gallery3d/photoeditor/filters/VignetteFilter.java b/src/com/android/gallery3d/photoeditor/filters/VignetteFilter.java
index ec39393..5903461 100644
--- a/src/com/android/gallery3d/photoeditor/filters/VignetteFilter.java
+++ b/src/com/android/gallery3d/photoeditor/filters/VignetteFilter.java
@@ -24,19 +24,9 @@
/**
* Vignette filter applied to the image.
*/
-public class VignetteFilter extends Filter {
+public class VignetteFilter extends AbstractScaleFilter {
- private float scale;
-
- /**
- * Sets the vignette range scale.
- *
- * @param scale ranges from 0 to 1.
- */
- public void setScale(float scale) {
- this.scale = scale;
- validate();
- }
+ public static final Creator<VignetteFilter> CREATOR = creatorOf(VignetteFilter.class);
@Override
public void process(Photo src, Photo dst) {
diff --git a/src/com/android/gallery3d/util/SpinnerVisibilitySetter.java b/src/com/android/gallery3d/util/SpinnerVisibilitySetter.java
index 75b1fa4..6ccc264 100644
--- a/src/com/android/gallery3d/util/SpinnerVisibilitySetter.java
+++ b/src/com/android/gallery3d/util/SpinnerVisibilitySetter.java
@@ -21,8 +21,7 @@
import android.os.Message;
import android.os.SystemClock;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.WeakHashMap;
/**
* This class manages the visibility of the progress spinner in the action bar for an
@@ -33,10 +32,8 @@
*/
public class SpinnerVisibilitySetter {
- private static final int SHOW_SPINNER_REQUESTED = 0;
- private static final int HIDE_SPINNER_REQUESTED = 1;
- private static final int SHOW_SPINNER_DELAY_REACHED = 2;
- private static final int HIDE_SPINNER_DELAY_REACHED = 3;
+ private static final int MSG_SHOW_SPINNER = 1;
+ private static final int MSG_HIDE_SPINNER = 2;
// Amount of time after a show request that the progress spinner is actually made visible.
// This means that any show/hide requests that happen subsequently within this period
@@ -46,88 +43,64 @@
// The minimum amount of time the progress spinner must be visible before it can be hidden.
private static final long MIN_SPINNER_DISPLAY_TIME = 2000;
- private boolean mPendingVisibilityRequest = false;
- private boolean mActiveVisibilityRequest = false;
- private long mSpinnerVisibilityStartTime;
+ static final WeakHashMap<Activity, SpinnerVisibilitySetter> sInstanceMap =
+ new WeakHashMap<Activity, SpinnerVisibilitySetter>();
- Handler mHandler = new Handler() {
+ private long mSpinnerVisibilityStartTime = -1;
+ private Activity mActivity;
+ private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
- case SHOW_SPINNER_REQUESTED:
- mPendingVisibilityRequest = true;
- sendEmptyMessageDelayed(SHOW_SPINNER_DELAY_REACHED, SPINNER_DISPLAY_DELAY);
+ case MSG_SHOW_SPINNER:
+ removeMessages(MSG_SHOW_SPINNER);
+ if (mSpinnerVisibilityStartTime >= 0) break;
+ mSpinnerVisibilityStartTime = SystemClock.elapsedRealtime();
+ mActivity.setProgressBarIndeterminateVisibility(true);
break;
- case HIDE_SPINNER_REQUESTED:
- mPendingVisibilityRequest = false;
- if (!mActiveVisibilityRequest) {
- // We haven't requested to show the spinner so no need to decide
- // when to hide it.
- break;
- }
-
- long currTime = SystemClock.uptimeMillis();
- if (currTime - mSpinnerVisibilityStartTime > MIN_SPINNER_DISPLAY_TIME) {
- // The spinner has already been visible longer than the requisite min
- // display time. Send the hide message immediately.
- sendEmptyMessage(HIDE_SPINNER_DELAY_REACHED);
+ case MSG_HIDE_SPINNER:
+ removeMessages(MSG_HIDE_SPINNER);
+ if (mSpinnerVisibilityStartTime < 0) break;
+ long t = SystemClock.elapsedRealtime() - mSpinnerVisibilityStartTime;
+ if (t >= MIN_SPINNER_DISPLAY_TIME) {
+ mSpinnerVisibilityStartTime = -1;
+ mActivity.setProgressBarIndeterminateVisibility(false);
} else {
- // The spinner is visible but hasn't been visible for long enough yet.
- // Send a delayed hide message.
- sendEmptyMessageAtTime(HIDE_SPINNER_DELAY_REACHED,
- mSpinnerVisibilityStartTime + MIN_SPINNER_DISPLAY_TIME);
+ sendEmptyMessageDelayed(MSG_HIDE_SPINNER, MIN_SPINNER_DISPLAY_TIME - t);
}
break;
- case SHOW_SPINNER_DELAY_REACHED:
- if (mPendingVisibilityRequest) {
- mPendingVisibilityRequest = false;
- mActiveVisibilityRequest = true;
-
- // Even though the spinner isn't visible quite yet, lets set this
- // here to avoid possible cross-thread synchronization issues.
- mSpinnerVisibilityStartTime = SystemClock.uptimeMillis();
- mActivity.runOnUiThread(new SetProgressVisibilityRunnable(true));
- }
- break;
- case HIDE_SPINNER_DELAY_REACHED:
- mActiveVisibilityRequest = false;
- mActivity.runOnUiThread(new SetProgressVisibilityRunnable(false));
- break;
}
}
};
- static final Map<Activity, SpinnerVisibilitySetter> sInstanceMap =
- new HashMap<Activity, SpinnerVisibilitySetter>();
- private Activity mActivity;
+
+ /**
+ * Gets the <code>SpinnerVisibilitySetter</code> for the given <code>activity</code>.
+ *
+ * This method must be called from the main thread.
+ */
+ public static SpinnerVisibilitySetter getInstance(Activity activity) {
+ synchronized(sInstanceMap) {
+ SpinnerVisibilitySetter setter = sInstanceMap.get(activity);
+ if (setter == null) {
+ setter = new SpinnerVisibilitySetter(activity);
+ sInstanceMap.put(activity, setter);
+ }
+ return setter;
+ }
+ }
private SpinnerVisibilitySetter(Activity activity) {
mActivity = activity;
}
- public static SpinnerVisibilitySetter getInstance(Activity activity) {
- synchronized(sInstanceMap) {
- if (sInstanceMap.get(activity) == null) {
- sInstanceMap.put(activity, new SpinnerVisibilitySetter(activity));
- }
- return sInstanceMap.get(activity);
- }
- }
-
public void setSpinnerVisibility(boolean visible) {
- mHandler.sendEmptyMessage(visible ? SHOW_SPINNER_REQUESTED : HIDE_SPINNER_REQUESTED);
- }
-
- private class SetProgressVisibilityRunnable implements Runnable {
- boolean mVisible;
-
- public SetProgressVisibilityRunnable(boolean visible) {
- mVisible = visible;
- }
-
- @Override
- public void run() {
- mActivity.setProgressBarIndeterminateVisibility(mVisible);
+ if (visible) {
+ mHandler.removeMessages(MSG_HIDE_SPINNER);
+ mHandler.sendEmptyMessageDelayed(MSG_SHOW_SPINNER, SPINNER_DISPLAY_DELAY);
+ } else {
+ mHandler.removeMessages(MSG_SHOW_SPINNER);
+ mHandler.sendEmptyMessage(MSG_HIDE_SPINNER);
}
}
}