OSDN Git Service

Refactor to remove obsolete design and improve code consistency.
authorYuli Huang <yuli@google.com>
Mon, 28 Nov 2011 12:05:27 +0000 (20:05 +0800)
committerYuli Huang <yuli@google.com>
Thu, 1 Dec 2011 16:57:02 +0000 (00:57 +0800)
1. Remove isValid()/validate() in Filter; EffectAction would push
filters into the stack when being notified by notifyChanged().
2. Make RedEyeAction consistent with DoodleAction by ignoring
out-of-bounds operations.
3. Improve consistency by encapsulate effect-tool creation/removal in
one class (EffectToolFactory).
4. Minimize variable visibility in EffectAction subclasses.
5. Fix unfinished doodle lost when exiting Doodle effect by multi-touch.

Change-Id: I8d3b127c5fe8777eb45b7c5ae680f6a30a99635a

56 files changed:
res/layout/photoeditor_crop_view.xml
res/layout/photoeditor_doodle_view.xml
res/layout/photoeditor_effect_tool_fullscreen.xml [new file with mode: 0644]
res/layout/photoeditor_flip_view.xml
res/layout/photoeditor_rotate_view.xml
res/layout/photoeditor_touch_view.xml
src/com/android/gallery3d/photoeditor/EffectsBar.java
src/com/android/gallery3d/photoeditor/actions/AutoFixAction.java
src/com/android/gallery3d/photoeditor/actions/ColorTemperatureAction.java
src/com/android/gallery3d/photoeditor/actions/CropAction.java
src/com/android/gallery3d/photoeditor/actions/CrossProcessAction.java
src/com/android/gallery3d/photoeditor/actions/DocumentaryAction.java
src/com/android/gallery3d/photoeditor/actions/Doodle.java
src/com/android/gallery3d/photoeditor/actions/DoodleAction.java
src/com/android/gallery3d/photoeditor/actions/DoodleView.java
src/com/android/gallery3d/photoeditor/actions/DuotoneAction.java
src/com/android/gallery3d/photoeditor/actions/EffectAction.java
src/com/android/gallery3d/photoeditor/actions/EffectToolFactory.java
src/com/android/gallery3d/photoeditor/actions/FaceTanAction.java
src/com/android/gallery3d/photoeditor/actions/FaceliftAction.java
src/com/android/gallery3d/photoeditor/actions/FillLightAction.java
src/com/android/gallery3d/photoeditor/actions/FisheyeAction.java
src/com/android/gallery3d/photoeditor/actions/FlipAction.java
src/com/android/gallery3d/photoeditor/actions/GrainAction.java
src/com/android/gallery3d/photoeditor/actions/GrayscaleAction.java
src/com/android/gallery3d/photoeditor/actions/HighlightAction.java
src/com/android/gallery3d/photoeditor/actions/LomoishAction.java
src/com/android/gallery3d/photoeditor/actions/NegativeAction.java
src/com/android/gallery3d/photoeditor/actions/PosterizeAction.java
src/com/android/gallery3d/photoeditor/actions/RedEyeAction.java
src/com/android/gallery3d/photoeditor/actions/RotateAction.java
src/com/android/gallery3d/photoeditor/actions/SaturationAction.java
src/com/android/gallery3d/photoeditor/actions/SepiaAction.java
src/com/android/gallery3d/photoeditor/actions/ShadowAction.java
src/com/android/gallery3d/photoeditor/actions/SharpenAction.java
src/com/android/gallery3d/photoeditor/actions/StraightenAction.java
src/com/android/gallery3d/photoeditor/actions/TintAction.java
src/com/android/gallery3d/photoeditor/actions/TouchView.java
src/com/android/gallery3d/photoeditor/actions/VignetteAction.java
src/com/android/gallery3d/photoeditor/filters/AbstractScaleFilter.java
src/com/android/gallery3d/photoeditor/filters/CropFilter.java
src/com/android/gallery3d/photoeditor/filters/CrossProcessFilter.java
src/com/android/gallery3d/photoeditor/filters/DocumentaryFilter.java
src/com/android/gallery3d/photoeditor/filters/DoodleFilter.java
src/com/android/gallery3d/photoeditor/filters/DuotoneFilter.java
src/com/android/gallery3d/photoeditor/filters/Filter.java
src/com/android/gallery3d/photoeditor/filters/FlipFilter.java
src/com/android/gallery3d/photoeditor/filters/GrayscaleFilter.java
src/com/android/gallery3d/photoeditor/filters/LomoishFilter.java
src/com/android/gallery3d/photoeditor/filters/NegativeFilter.java
src/com/android/gallery3d/photoeditor/filters/PosterizeFilter.java
src/com/android/gallery3d/photoeditor/filters/RedEyeFilter.java
src/com/android/gallery3d/photoeditor/filters/RotateFilter.java
src/com/android/gallery3d/photoeditor/filters/SepiaFilter.java
src/com/android/gallery3d/photoeditor/filters/StraightenFilter.java
src/com/android/gallery3d/photoeditor/filters/TintFilter.java

index 151e6a6..bf5cacb 100644 (file)
@@ -16,5 +16,4 @@
 
 <com.android.gallery3d.photoeditor.actions.CropView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/fullscreen_effect_tool"
     style="@style/FullscreenToolView"/>
index d8e0868..c202f14 100644 (file)
@@ -16,5 +16,4 @@
 
 <com.android.gallery3d.photoeditor.actions.DoodleView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/fullscreen_effect_tool"
     style="@style/FullscreenToolView"/>
diff --git a/res/layout/photoeditor_effect_tool_fullscreen.xml b/res/layout/photoeditor_effect_tool_fullscreen.xml
new file mode 100644 (file)
index 0000000..a6dd323
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"/>
index 0b7a7a7..150b24e 100644 (file)
@@ -16,5 +16,4 @@
 
 <com.android.gallery3d.photoeditor.actions.FlipView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/fullscreen_effect_tool"
     style="@style/FullscreenToolView"/>
index 9dbe9d0..0e85fd4 100644 (file)
@@ -16,5 +16,4 @@
 
 <com.android.gallery3d.photoeditor.actions.RotateView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/fullscreen_effect_tool"
     style="@style/FullscreenToolView"/>
index 39a0871..a6da078 100644 (file)
@@ -16,5 +16,4 @@
 
 <com.android.gallery3d.photoeditor.actions.TouchView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/fullscreen_effect_tool"
     style="@style/FullscreenToolView"/>
index 4075404..1aafc4e 100644 (file)
@@ -92,6 +92,7 @@ public class EffectsBar extends LinearLayout {
                     activeEffect = effect;
                     exitEffectsGallery();
                     // Create effect tool panel first before the factory could create tools within.
+                    // TODO: Refactor to encapsulate effect-tool panel in effect-tool factory.
                     createEffectToolPanel();
                     activeEffect.begin(filterStack,
                             new EffectToolFactory(effectToolPanel, inflater));
@@ -134,11 +135,6 @@ public class EffectsBar extends LinearLayout {
                 @Override
                 public void run() {
                     SpinnerProgressDialog.dismissDialog();
-                    View fullscreenTool = getRootView().findViewById(R.id.fullscreen_effect_tool);
-                    if (fullscreenTool != null) {
-                        ((ViewGroup) fullscreenTool.getParent()).removeView(fullscreenTool);
-                    }
-                    removeView(effectToolPanel);
                     effectToolPanel = null;
                     activeEffect = null;
                     if (runnableOnDone != null) {
index 26b5f51..6b3f184 100644 (file)
@@ -33,14 +33,10 @@ public class AutoFixAction extends EffectAction {
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         AutoFixFilter filter = new AutoFixFilter();
         filter.setScale(DEFAULT_SCALE);
-        notifyFilterChanged(filter, true);
+        notifyChanged(filter);
         notifyDone();
     }
-
-    @Override
-    public void doEnd() {
-    }
 }
index 24978fa..ac329a0 100644 (file)
@@ -28,32 +28,25 @@ public class ColorTemperatureAction extends EffectAction {
 
     private static final float DEFAULT_SCALE = 0.5f;
 
-    private ScaleSeekBar scalePicker;
-
     public ColorTemperatureAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final ColorTemperatureFilter filter = new ColorTemperatureFilter();
 
-        scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.COLOR);
+        ScaleSeekBar scalePicker = factory.createScalePicker(EffectToolFactory.ScaleType.COLOR);
         scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
 
             @Override
             public void onProgressChanged(float progress, boolean fromUser) {
                 if (fromUser) {
                     filter.setScale(progress);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         scalePicker.setProgress(DEFAULT_SCALE);
     }
-
-    @Override
-    public void doEnd() {
-        scalePicker.setOnScaleChangeListener(null);
-    }
 }
index 60a0179..0a3d12f 100644 (file)
@@ -29,25 +29,24 @@ public class CropAction extends EffectAction {
 
     private static final float DEFAULT_CROP = 0.2f;
 
-    private CropFilter filter;
-    private CropView cropView;
-
     public CropAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
-        filter = new CropFilter();
+    public void prepare() {
+        // Cropped results wouldn't be previewed for changed crop bounds.
+        final CropFilter filter = new CropFilter();
+        disableFilterOutput();
 
-        cropView = factory.createCropView();
+        CropView cropView = factory.createCropView();
         cropView.setOnCropChangeListener(new CropView.OnCropChangeListener() {
 
             @Override
             public void onCropChanged(RectF cropBounds, boolean fromUser) {
                 if (fromUser) {
                     filter.setCropBounds(cropBounds);
-                    notifyFilterChanged(filter, false);
+                    notifyChanged(filter);
                 }
             }
         });
@@ -55,12 +54,6 @@ public class CropAction extends EffectAction {
         RectF bounds = new RectF(DEFAULT_CROP, DEFAULT_CROP, 1 - DEFAULT_CROP, 1 - DEFAULT_CROP);
         cropView.setCropBounds(bounds);
         filter.setCropBounds(bounds);
-        notifyFilterChanged(filter, false);
-    }
-
-    @Override
-    public void doEnd() {
-        cropView.setOnCropChangeListener(null);
-        notifyFilterChanged(filter, true);
+        notifyChanged(filter);
     }
 }
index 8be60d3..7369dc5 100644 (file)
@@ -31,12 +31,8 @@ public class CrossProcessAction extends EffectAction {
     }
 
     @Override
-    public void doBegin() {
-        notifyFilterChanged(new CrossProcessFilter(), true);
+    public void prepare() {
+        notifyChanged(new CrossProcessFilter());
         notifyDone();
     }
-
-    @Override
-    public void doEnd() {
-    }
 }
index 0ec4a02..d1fd611 100644 (file)
@@ -31,12 +31,8 @@ public class DocumentaryAction extends EffectAction {
     }
 
     @Override
-    public void doBegin() {
-        notifyFilterChanged(new DocumentaryFilter(), true);
+    public void prepare() {
+        notifyChanged(new DocumentaryFilter());
         notifyDone();
     }
-
-    @Override
-    public void doEnd() {
-    }
 }
index ea23e23..bd08983 100644 (file)
@@ -55,18 +55,21 @@ public class Doodle implements Parcelable {
     }
 
     /**
+     * Checks if the constructed doodle path is in (0, 0, 1, 1) bounds.
+     */
+    public boolean inBounds() {
+        RectF r = new RectF();
+        normalizedPath.computeBounds(r, false);
+        return r.intersects(0, 0, 1, 1);
+    }
+
+    /**
      * 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) {
+    public void 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() {
index 4ad2cfb..ca999c1 100644 (file)
@@ -28,53 +28,47 @@ public class DoodleAction extends EffectAction {
 
     private static final int DEFAULT_COLOR_INDEX = 4;
 
-    private DoodleFilter filter;
-    private ColorSeekBar colorPicker;
-    private DoodleView doodleView;
-
     public DoodleAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
-        filter = new DoodleFilter();
+    public void prepare() {
+        // Directly draw on doodle-view because running the doodle filter isn't fast enough.
+        final DoodleFilter filter = new DoodleFilter();
+        disableFilterOutput();
 
-        colorPicker = factory.createColorPicker();
-        colorPicker.setOnColorChangeListener(new ColorSeekBar.OnColorChangeListener() {
+        final DoodleView doodleView = factory.createDoodleView();
+        doodleView.setOnDoodleChangeListener(new DoodleView.OnDoodleChangeListener() {
 
             @Override
-            public void onColorChanged(int color, boolean fromUser) {
-                if (fromUser) {
-                    doodleView.setColor(color);
+            public void onDoodleChanged(Doodle doodle) {
+                // Check if the user draws within photo bounds and makes visible changes on photo.
+                if (doodle.inBounds()) {
+                    notifyChanged(filter);
                 }
             }
-        });
-        colorPicker.setColorIndex(DEFAULT_COLOR_INDEX);
-
-        doodleView = factory.createDoodleView();
-        doodleView.setOnDoodleChangeListener(new DoodleView.OnDoodleChangeListener() {
 
             @Override
-            public void onDoodleInPhotoBounds() {
-                // Notify the user has drawn within photo bounds and made visible changes on photo.
-                filter.setDoodledInPhotoBounds();
-                notifyFilterChanged(filter, false);
+            public void onDoodleFinished(Doodle doodle) {
+                if (doodle.inBounds()) {
+                    filter.addDoodle(doodle);
+                    notifyChanged(filter);
+                }
             }
+        });
+
+        ColorSeekBar colorPicker = factory.createColorPicker();
+        colorPicker.setOnColorChangeListener(new ColorSeekBar.OnColorChangeListener() {
 
             @Override
-            public void onDoodleFinished(Doodle doodle) {
-                filter.addDoodle(doodle);
-                notifyFilterChanged(filter, false);
+            public void onColorChanged(int color, boolean fromUser) {
+                if (fromUser) {
+                    doodleView.setColor(color);
+                }
             }
         });
+        colorPicker.setColorIndex(DEFAULT_COLOR_INDEX);
         doodleView.setColor(colorPicker.getColor());
     }
-
-    @Override
-    public void doEnd() {
-        colorPicker.setOnColorChangeListener(null);
-        doodleView.setOnDoodleChangeListener(null);
-        notifyFilterChanged(filter, true);
-    }
 }
index b596861..d396049 100644 (file)
@@ -37,7 +37,7 @@ class DoodleView extends FullscreenToolView {
      */
     public interface OnDoodleChangeListener {
 
-        void onDoodleInPhotoBounds();
+        void onDoodleChanged(Doodle doodle);
 
         void onDoodleFinished(Doodle doodle);
     }
@@ -111,9 +111,10 @@ class DoodleView extends FullscreenToolView {
     }
 
     private void addLastPointIntoDoodle() {
-        if ((doodle != null) && doodle.addControlPoint(new PointF(lastPoint.x, lastPoint.y))) {
+        if (doodle != null) {
+            doodle.addControlPoint(new PointF(lastPoint.x, lastPoint.y));
             if (listener != null) {
-                listener.onDoodleInPhotoBounds();
+                listener.onDoodleChanged(doodle);
             }
             invalidate();
         }
index b8da71e..57082c0 100644 (file)
@@ -34,15 +34,11 @@ public class DuotoneAction extends EffectAction {
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         // TODO: Add several sets of duo-tone colors to select from.
         DuotoneFilter filter = new DuotoneFilter();
         filter.setDuotone(DEFAULT_FIRST_COLOR, DEFAULT_SECOND_COLOR);
-        notifyFilterChanged(filter, true);
+        notifyChanged(filter);
         notifyDone();
     }
-
-    @Override
-    public void doEnd() {
-    }
 }
index 6c6a893..c17ec23 100644 (file)
@@ -45,11 +45,11 @@ public abstract class EffectAction extends LinearLayout {
     }
 
     protected EffectToolFactory factory;
-
     private Listener listener;
     private Toast tooltip;
     private FilterStack filterStack;
     private boolean pushedFilter;
+    private boolean disableFilterOutput;
     private FilterChangedCallback lastFilterChangedCallback;
 
     public EffectAction(Context context, AttributeSet attrs) {
@@ -84,14 +84,24 @@ public abstract class EffectAction extends LinearLayout {
             tooltip.setGravity(Gravity.CENTER, 0, 0);
             tooltip.show();
         }
-        doBegin();
+        prepare();
     }
 
     /**
+     * Subclasses should create a specific filter and bind the filter to necessary UI controls here
+     * when the action is about to begin.
+     */
+    protected abstract void prepare();
+
+    /**
      * Ends the effect and then executes the runnable after the effect is finished.
      */
     public void end(final Runnable runnableOnODone) {
-        doEnd();
+        // Remove created tools before ending and output the pushed filter if it wasn't outputted.
+        factory.removeTools();
+        if (pushedFilter && disableFilterOutput) {
+            outputFilter();
+        }
 
         // Wait till last output callback is done before finishing.
         if ((lastFilterChangedCallback == null) || lastFilterChangedCallback.done) {
@@ -114,39 +124,38 @@ public abstract class EffectAction extends LinearLayout {
             tooltip = null;
         }
         pushedFilter = false;
+        disableFilterOutput = false;
         lastFilterChangedCallback = null;
 
         runnableOnDone.run();
     }
 
-    protected void notifyDone() {
-        if (listener != null) {
-            listener.onDone();
-        }
+    protected void disableFilterOutput() {
+        // Filter output won't be outputted until this effect has done editing its filter.
+        disableFilterOutput = true;
+    }
+
+    protected void outputFilter() {
+        // Notify the stack to execute the changed top filter and output the results.
+        lastFilterChangedCallback = new FilterChangedCallback();
+        filterStack.topFilterChanged(lastFilterChangedCallback);
     }
 
-    protected void notifyFilterChanged(Filter filter, boolean output) {
-        if (!pushedFilter && filter.isValid()) {
+    protected void notifyChanged(Filter filter) {
+        if (!pushedFilter) {
             filterStack.pushFilter(filter);
             pushedFilter = true;
         }
-        if (pushedFilter && output) {
-            // Notify the stack to execute the changed top filter and output the results.
-            lastFilterChangedCallback = new FilterChangedCallback();
-            filterStack.topFilterChanged(lastFilterChangedCallback);
+        if (pushedFilter && !disableFilterOutput) {
+            outputFilter();
         }
     }
 
-    /**
-     * Subclasses should creates a specific filter and binds the filter to necessary UI controls
-     * here when the action is about to begin.
-     */
-    protected abstract void doBegin();
-
-    /**
-     * Subclasses could do specific ending operations here when the action is about to end.
-     */
-    protected abstract void doEnd();
+    protected void notifyDone() {
+        if (listener != null) {
+            listener.onDone();
+        }
+    }
 
     /**
      * Done callback for executing top filter changes.
index 3641828..f68db8b 100644 (file)
@@ -28,36 +28,54 @@ import com.android.gallery3d.photoeditor.PhotoView;
  */
 public class EffectToolFactory {
 
-    public enum ScalePickerType {
+    public enum ScaleType {
         LIGHT, SHADOW, COLOR, GENERIC
     }
 
     private final ViewGroup effectToolPanel;
     private final LayoutInflater inflater;
+    private ViewGroup effectToolFullscreen;
 
     public EffectToolFactory(ViewGroup effectToolPanel, LayoutInflater inflater) {
         this.effectToolPanel = effectToolPanel;
         this.inflater = inflater;
     }
 
+    public PhotoView getPhotoView() {
+        return (PhotoView) effectToolPanel.getRootView().findViewById(R.id.photo_view);
+    }
+
+    public void removeTools() {
+        // Remove all created tools.
+        if (effectToolFullscreen != null) {
+            ((ViewGroup) effectToolFullscreen.getParent()).removeView(effectToolFullscreen);
+            effectToolFullscreen = null;
+        }
+        ((ViewGroup) effectToolPanel.getParent()).removeView(effectToolPanel);
+    }
+
     private View createFullscreenTool(int toolId) {
         // Create full screen effect tool on top of photo-view and place it within the same
         // view group that contains photo-view.
-        View photoView = effectToolPanel.getRootView().findViewById(R.id.photo_view);
+        PhotoView photoView = getPhotoView();
         ViewGroup parent = (ViewGroup) photoView.getParent();
-        FullscreenToolView view = (FullscreenToolView) inflater.inflate(toolId, parent, false);
-        view.setPhotoBounds(((PhotoView) photoView).getPhotoBounds());
-        parent.addView(view, parent.indexOfChild(photoView) + 1);
-        return view;
+        effectToolFullscreen = (ViewGroup) inflater.inflate(
+                R.layout.photoeditor_effect_tool_fullscreen, parent, false);
+        parent.addView(effectToolFullscreen, parent.indexOfChild(photoView) + 1);
+        FullscreenToolView tool = (FullscreenToolView) inflater.inflate(
+                toolId, effectToolFullscreen, false);
+        tool.setPhotoBounds(photoView.getPhotoBounds());
+        effectToolFullscreen.addView(tool);
+        return tool;
     }
 
     private View createPanelTool(int toolId) {
-        View view = inflater.inflate(toolId, effectToolPanel, false);
-        effectToolPanel.addView(view, 0);
-        return view;
+        View tool = inflater.inflate(toolId, effectToolPanel, false);
+        effectToolPanel.addView(tool);
+        return tool;
     }
 
-    private int getScalePickerBackground(ScalePickerType type) {
+    private int getScalePickerBackground(ScaleType type) {
         switch (type) {
             case LIGHT:
                 return R.drawable.photoeditor_scale_seekbar_light;
@@ -71,7 +89,7 @@ public class EffectToolFactory {
         return R.drawable.photoeditor_scale_seekbar_generic;
     }
 
-    public ScaleSeekBar createScalePicker(ScalePickerType type) {
+    public ScaleSeekBar createScalePicker(ScaleType type) {
         ScaleSeekBar scalePicker = (ScaleSeekBar) createPanelTool(
                 R.layout.photoeditor_scale_seekbar);
         scalePicker.setBackgroundResource(getScalePickerBackground(type));
index a82f330..6faa778 100644 (file)
@@ -28,35 +28,28 @@ 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() {
+    public void prepare() {
         final FaceTanFilter filter = new FaceTanFilter();
 
-        scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.GENERIC);
+        ScaleSeekBar scalePicker = factory.createScalePicker(EffectToolFactory.ScaleType.GENERIC);
         scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
 
             @Override
             public void onProgressChanged(float progress, boolean fromUser) {
                 if (fromUser) {
                     filter.setScale(progress);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         scalePicker.setProgress(DEFAULT_SCALE);
 
         filter.setScale(DEFAULT_SCALE);
-        notifyFilterChanged(filter, true);
-    }
-
-    @Override
-    public void doEnd() {
-        scalePicker.setOnScaleChangeListener(null);
+        notifyChanged(filter);
     }
 }
index 90d4e0c..9afa7ba 100644 (file)
@@ -28,35 +28,28 @@ public class FaceliftAction extends EffectAction {
 
     private static final float DEFAULT_SCALE = 0.5f;
 
-    private ScaleSeekBar scalePicker;
-
     public FaceliftAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final FaceliftFilter filter = new FaceliftFilter();
 
-        scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.GENERIC);
+        ScaleSeekBar scalePicker = factory.createScalePicker(EffectToolFactory.ScaleType.GENERIC);
         scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
 
             @Override
             public void onProgressChanged(float progress, boolean fromUser) {
                 if (fromUser) {
                     filter.setScale(progress);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         scalePicker.setProgress(DEFAULT_SCALE);
 
         filter.setScale(DEFAULT_SCALE);
-        notifyFilterChanged(filter, true);
-    }
-
-    @Override
-    public void doEnd() {
-        scalePicker.setOnScaleChangeListener(null);
+        notifyChanged(filter);
     }
 }
index 73cf3d8..dbb52b5 100644 (file)
@@ -28,32 +28,25 @@ public class FillLightAction extends EffectAction {
 
     private static final float DEFAULT_SCALE = 0f;
 
-    private ScaleSeekBar scalePicker;
-
     public FillLightAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final FillLightFilter filter = new FillLightFilter();
 
-        scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.LIGHT);
+        ScaleSeekBar scalePicker = factory.createScalePicker(EffectToolFactory.ScaleType.LIGHT);
         scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
 
             @Override
             public void onProgressChanged(float progress, boolean fromUser) {
                 if (fromUser) {
                     filter.setScale(progress);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         scalePicker.setProgress(DEFAULT_SCALE);
     }
-
-    @Override
-    public void doEnd() {
-        scalePicker.setOnScaleChangeListener(null);
-    }
 }
index 348f004..fdff064 100644 (file)
@@ -28,35 +28,28 @@ public class FisheyeAction extends EffectAction {
 
     private static final float DEFAULT_SCALE = 0.5f;
 
-    private ScaleSeekBar scalePicker;
-
     public FisheyeAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final FisheyeFilter filter = new FisheyeFilter();
 
-        scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.GENERIC);
+        ScaleSeekBar scalePicker = factory.createScalePicker(EffectToolFactory.ScaleType.GENERIC);
         scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
 
             @Override
             public void onProgressChanged(float progress, boolean fromUser) {
                 if (fromUser) {
                     filter.setScale(progress);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         scalePicker.setProgress(DEFAULT_SCALE);
 
         filter.setScale(DEFAULT_SCALE);
-        notifyFilterChanged(filter, true);
-    }
-
-    @Override
-    public void doEnd() {
-        scalePicker.setOnScaleChangeListener(null);
+        notifyChanged(filter);
     }
 }
index da238ba..6381d7f 100644 (file)
@@ -19,7 +19,6 @@ package com.android.gallery3d.photoeditor.actions;
 import android.content.Context;
 import android.util.AttributeSet;
 
-import com.android.gallery3d.R;
 import com.android.gallery3d.photoeditor.PhotoView;
 import com.android.gallery3d.photoeditor.filters.FlipFilter;
 
@@ -31,35 +30,32 @@ public class FlipAction extends EffectAction {
     private static final float DEFAULT_ANGLE = 0.0f;
     private static final float DEFAULT_FLIP_SPAN = 180.0f;
 
-    private FlipFilter filter;
-    private float horizontalFlipDegrees;
-    private float verticalFlipDegrees;
-    private Runnable queuedFlipChange;
-    private FlipView flipView;
-
     public FlipAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
-        filter = new FlipFilter();
+    public void prepare() {
+        // Disable outputting flipped results and directly flip photo-view for animations.
+        final FlipFilter filter = new FlipFilter();
+        disableFilterOutput();
 
-        flipView = factory.createFlipView();
+        final FlipView flipView = factory.createFlipView();
         flipView.setOnFlipChangeListener(new FlipView.OnFlipChangeListener() {
 
-            // Directly transform photo-view because running the flip filter isn't fast enough.
-            PhotoView photoView = (PhotoView) flipView.getRootView().findViewById(
-                    R.id.photo_view);
+            float horizontalDegrees;
+            float verticalDegrees;
+            Runnable queuedTransform;
+            PhotoView photoView = factory.getPhotoView();
 
             @Override
             public void onAngleChanged(float horizontalDegrees, float verticalDegrees,
                     boolean fromUser) {
                 if (fromUser) {
-                    horizontalFlipDegrees = horizontalDegrees;
-                    verticalFlipDegrees = verticalDegrees;
-                    updateFlipFilter(false);
+                    this.horizontalDegrees = horizontalDegrees;
+                    this.verticalDegrees = verticalDegrees;
                     transformPhotoView(horizontalDegrees, verticalDegrees);
+                    notifyChanged(filter);
                 }
             }
 
@@ -70,59 +66,42 @@ public class FlipAction extends EffectAction {
 
             @Override
             public void onStopTrackingTouch() {
-                roundFlipDegrees();
-                updateFlipFilter(false);
-                transformPhotoView(horizontalFlipDegrees, verticalFlipDegrees);
-                flipView.setFlippedAngles(horizontalFlipDegrees, verticalFlipDegrees);
+                // Round flip degrees to multiples of 180 degrees.
+                horizontalDegrees = roundTo180(horizontalDegrees);
+                verticalDegrees = roundTo180(verticalDegrees);
+                transformPhotoView(horizontalDegrees, verticalDegrees);
+                flipView.setFlippedAngles(horizontalDegrees, verticalDegrees);
+
+                // Flip the filter according to the flipped directions of flip-view.
+                filter.setFlip(((int) horizontalDegrees / 180) % 2 != 0,
+                        ((int) verticalDegrees / 180) % 2 != 0);
+                notifyChanged(filter);
+            }
+
+            private float roundTo180(float degrees) {
+                if (degrees % 180 != 0) {
+                    degrees = Math.round(degrees / 180) * 180;
+                }
+                return degrees;
             }
 
             private void transformPhotoView(final float horizontalDegrees,
                     final float verticalDegrees) {
                 // Remove the outdated flip change before queuing a new one.
-                if (queuedFlipChange != null) {
-                    photoView.remove(queuedFlipChange);
+                if (queuedTransform != null) {
+                    photoView.remove(queuedTransform);
                 }
-                queuedFlipChange = new Runnable() {
+                queuedTransform = new Runnable() {
 
                     @Override
                     public void run() {
                         photoView.flipPhoto(horizontalDegrees, verticalDegrees);
                     }
                 };
-                photoView.queue(queuedFlipChange);
+                photoView.queue(queuedTransform);
             }
         });
         flipView.setFlippedAngles(DEFAULT_ANGLE, DEFAULT_ANGLE);
         flipView.setFlipSpan(DEFAULT_FLIP_SPAN);
-        horizontalFlipDegrees = 0;
-        verticalFlipDegrees = 0;
-        queuedFlipChange = null;
-    }
-
-    @Override
-    public void doEnd() {
-        flipView.setOnFlipChangeListener(null);
-        // Round the current flip degrees in case flip tracking has not stopped yet.
-        roundFlipDegrees();
-        updateFlipFilter(true);
-    }
-
-    /**
-     * Rounds flip degrees to multiples of 180 degrees.
-     */
-    private void roundFlipDegrees() {
-        if (horizontalFlipDegrees % 180 != 0) {
-            horizontalFlipDegrees = Math.round(horizontalFlipDegrees / 180) * 180;
-        }
-        if (verticalFlipDegrees % 180 != 0) {
-            verticalFlipDegrees = Math.round(verticalFlipDegrees / 180) * 180;
-        }
-    }
-
-    private void updateFlipFilter(boolean outputFilter) {
-        // Flip the filter if the flipped degrees are at the opposite directions.
-        filter.setFlip(((int) horizontalFlipDegrees / 180) % 2 != 0,
-                ((int) verticalFlipDegrees / 180) % 2 != 0);
-        notifyFilterChanged(filter, outputFilter);
     }
 }
index 258eb8a..4f64321 100644 (file)
@@ -28,35 +28,28 @@ public class GrainAction extends EffectAction {
 
     private static final float DEFAULT_SCALE = 0.5f;
 
-    private ScaleSeekBar scalePicker;
-
     public GrainAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final GrainFilter filter = new GrainFilter();
 
-        scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.GENERIC);
+        ScaleSeekBar scalePicker = factory.createScalePicker(EffectToolFactory.ScaleType.GENERIC);
         scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
 
             @Override
             public void onProgressChanged(float progress, boolean fromUser) {
                 if (fromUser) {
                     filter.setScale(progress);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         scalePicker.setProgress(DEFAULT_SCALE);
 
         filter.setScale(DEFAULT_SCALE);
-        notifyFilterChanged(filter, true);
-    }
-
-    @Override
-    public void doEnd() {
-        scalePicker.setOnScaleChangeListener(null);
+        notifyChanged(filter);
     }
 }
index ac89cd1..3ec468c 100644 (file)
@@ -31,12 +31,8 @@ public class GrayscaleAction extends EffectAction {
     }
 
     @Override
-    public void doBegin() {
-        notifyFilterChanged(new GrayscaleFilter(), true);
+    public void prepare() {
+        notifyChanged(new GrayscaleFilter());
         notifyDone();
     }
-
-    @Override
-    public void doEnd() {
-    }
 }
index a3d62d2..fc06b73 100644 (file)
@@ -28,32 +28,25 @@ public class HighlightAction extends EffectAction {
 
     private static final float DEFAULT_SCALE = 0f;
 
-    private ScaleSeekBar scalePicker;
-
     public HighlightAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final HighlightFilter filter = new HighlightFilter();
 
-        scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.LIGHT);
+        ScaleSeekBar scalePicker = factory.createScalePicker(EffectToolFactory.ScaleType.LIGHT);
         scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
 
             @Override
             public void onProgressChanged(float progress, boolean fromUser) {
                 if (fromUser) {
                     filter.setScale(progress);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         scalePicker.setProgress(DEFAULT_SCALE);
     }
-
-    @Override
-    public void doEnd() {
-        scalePicker.setOnScaleChangeListener(null);
-    }
 }
index 44ffc52..2061f28 100644 (file)
@@ -31,12 +31,8 @@ public class LomoishAction extends EffectAction {
     }
 
     @Override
-    public void doBegin() {
-        notifyFilterChanged(new LomoishFilter(), true);
+    public void prepare() {
+        notifyChanged(new LomoishFilter());
         notifyDone();
     }
-
-    @Override
-    public void doEnd() {
-    }
 }
index 5276421..f7de871 100644 (file)
@@ -31,12 +31,8 @@ public class NegativeAction extends EffectAction {
     }
 
     @Override
-    public void doBegin() {
-        notifyFilterChanged(new NegativeFilter(), true);
+    public void prepare() {
+        notifyChanged(new NegativeFilter());
         notifyDone();
     }
-
-    @Override
-    public void doEnd() {
-    }
 }
index 760539d..5fde602 100644 (file)
@@ -31,12 +31,8 @@ public class PosterizeAction extends EffectAction {
     }
 
     @Override
-    public void doBegin() {
-        notifyFilterChanged(new PosterizeFilter(), true);
+    public void prepare() {
+        notifyChanged(new PosterizeFilter());
         notifyDone();
     }
-
-    @Override
-    public void doEnd() {
-    }
 }
index a472ad9..cea1aae 100644 (file)
@@ -18,6 +18,7 @@ package com.android.gallery3d.photoeditor.actions;
 
 import android.content.Context;
 import android.graphics.PointF;
+import android.graphics.RectF;
 import android.util.AttributeSet;
 
 import com.android.gallery3d.photoeditor.filters.RedEyeFilter;
@@ -27,29 +28,27 @@ import com.android.gallery3d.photoeditor.filters.RedEyeFilter;
  */
 public class RedEyeAction extends EffectAction {
 
-    private TouchView touchView;
-
     public RedEyeAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final RedEyeFilter filter = new RedEyeFilter();
 
-        touchView = factory.createTouchView();
+        TouchView touchView = factory.createTouchView();
         touchView.setSingleTapListener(new TouchView.SingleTapListener() {
 
+            final RectF bounds = new RectF(0, 0, 1, 1);
+
             @Override
             public void onSingleTap(PointF point) {
-                filter.addRedEyePosition(point);
-                notifyFilterChanged(filter, true);
+                // Check if the user taps within photo bounds to remove red eye on photo.
+                if (bounds.contains(point.x, point.y)) {
+                    filter.addRedEyePosition(point);
+                    notifyChanged(filter);
+                }
             }
         });
     }
-
-    @Override
-    public void doEnd() {
-        touchView.setSingleTapListener(null);
-    }
 }
index 36a09d9..8adf3e5 100644 (file)
@@ -19,7 +19,6 @@ package com.android.gallery3d.photoeditor.actions;
 import android.content.Context;
 import android.util.AttributeSet;
 
-import com.android.gallery3d.R;
 import com.android.gallery3d.photoeditor.PhotoView;
 import com.android.gallery3d.photoeditor.filters.RotateFilter;
 
@@ -31,32 +30,29 @@ public class RotateAction extends EffectAction {
     private static final float DEFAULT_ANGLE = 0.0f;
     private static final float DEFAULT_ROTATE_SPAN = 360.0f;
 
-    private RotateFilter filter;
-    private float rotateDegrees;
-    private Runnable queuedRotationChange;
-    private RotateView rotateView;
-
     public RotateAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
-        filter = new RotateFilter();
+    public void prepare() {
+        // Disable outputting rotated results and directly rotate photo-view for animations.
+        final RotateFilter filter = new RotateFilter();
+        disableFilterOutput();
 
-        rotateView = factory.createRotateView();
+        final RotateView rotateView = factory.createRotateView();
         rotateView.setOnRotateChangeListener(new RotateView.OnRotateChangeListener() {
 
-            // Directly transform photo-view because running the rotate filter isn't fast enough.
-            PhotoView photoView = (PhotoView) rotateView.getRootView().findViewById(
-                    R.id.photo_view);
+            float rotateDegrees;
+            Runnable queuedTransform;
+            PhotoView photoView = factory.getPhotoView();
 
             @Override
-            public void onAngleChanged(float degrees, boolean fromUser){
+            public void onAngleChanged(float degrees, boolean fromUser) {
                 if (fromUser) {
                     rotateDegrees = degrees;
-                    updateRotateFilter(false);
-                    transformPhotoView(degrees);
+                    transformPhotoView(rotateDegrees);
+                    notifyChanged(filter);
                 }
             }
 
@@ -67,52 +63,32 @@ public class RotateAction extends EffectAction {
 
             @Override
             public void onStopTrackingTouch() {
-                roundRotateDegrees();
-                updateRotateFilter(false);
+                // Round rotate degrees to multiples of 90 degrees.
+                if (rotateDegrees % 90 != 0) {
+                    rotateDegrees = Math.round(rotateDegrees / 90) * 90;
+                }
                 transformPhotoView(rotateDegrees);
                 rotateView.setRotatedAngle(rotateDegrees);
+                filter.setAngle(rotateDegrees);
+                notifyChanged(filter);
             }
 
             private void transformPhotoView(final float degrees) {
                 // Remove the outdated rotation change before queuing a new one.
-                if (queuedRotationChange != null) {
-                    photoView.remove(queuedRotationChange);
+                if (queuedTransform != null) {
+                    photoView.remove(queuedTransform);
                 }
-                queuedRotationChange = new Runnable() {
+                queuedTransform = new Runnable() {
 
                     @Override
                     public void run() {
                         photoView.rotatePhoto(degrees);
                     }
                 };
-                photoView.queue(queuedRotationChange);
+                photoView.queue(queuedTransform);
             }
         });
         rotateView.setRotatedAngle(DEFAULT_ANGLE);
         rotateView.setRotateSpan(DEFAULT_ROTATE_SPAN);
-        rotateDegrees = 0;
-        queuedRotationChange = null;
-    }
-
-    @Override
-    public void doEnd() {
-        rotateView.setOnRotateChangeListener(null);
-        // Round the current rotation degrees in case rotation tracking has not stopped yet.
-        roundRotateDegrees();
-        updateRotateFilter(true);
-    }
-
-    /**
-     * Rounds rotate degrees to multiples of 90 degrees.
-     */
-    private void roundRotateDegrees() {
-        if (rotateDegrees % 90 != 0) {
-            rotateDegrees = Math.round(rotateDegrees / 90) * 90;
-        }
-    }
-
-    private void updateRotateFilter(boolean outputFilter) {
-        filter.setAngle(rotateDegrees);
-        notifyFilterChanged(filter, outputFilter);
     }
 }
index 2f67e0a..b3ffe64 100644 (file)
@@ -28,32 +28,25 @@ public class SaturationAction extends EffectAction {
 
     private static final float DEFAULT_SCALE = 0.5f;
 
-    private ScaleSeekBar scalePicker;
-
     public SaturationAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final SaturationFilter filter = new SaturationFilter();
 
-        scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.COLOR);
+        ScaleSeekBar scalePicker = factory.createScalePicker(EffectToolFactory.ScaleType.COLOR);
         scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
 
             @Override
             public void onProgressChanged(float progress, boolean fromUser) {
                 if (fromUser) {
                     filter.setScale(progress);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         scalePicker.setProgress(DEFAULT_SCALE);
     }
-
-    @Override
-    public void doEnd() {
-        scalePicker.setOnScaleChangeListener(null);
-    }
 }
index c431115..96b33a0 100644 (file)
@@ -31,12 +31,8 @@ public class SepiaAction  extends EffectAction {
     }
 
     @Override
-    public void doBegin() {
-        notifyFilterChanged(new SepiaFilter(), true);
+    public void prepare() {
+        notifyChanged(new SepiaFilter());
         notifyDone();
     }
-
-    @Override
-    public void doEnd() {
-    }
 }
index 15ba850..87781af 100644 (file)
@@ -28,32 +28,25 @@ public class ShadowAction extends EffectAction {
 
     private static final float DEFAULT_SCALE = 0f;
 
-    private ScaleSeekBar scalePicker;
-
     public ShadowAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final ShadowFilter filter = new ShadowFilter();
 
-        scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.SHADOW);
+        ScaleSeekBar scalePicker = factory.createScalePicker(EffectToolFactory.ScaleType.SHADOW);
         scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
 
             @Override
             public void onProgressChanged(float progress, boolean fromUser) {
                 if (fromUser) {
                     filter.setScale(progress);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         scalePicker.setProgress(DEFAULT_SCALE);
     }
-
-    @Override
-    public void doEnd() {
-        scalePicker.setOnScaleChangeListener(null);
-    }
 }
index c6b240b..760f390 100644 (file)
@@ -28,35 +28,28 @@ public class SharpenAction extends EffectAction {
 
     private static final float DEFAULT_SCALE = 0.5f;
 
-    private ScaleSeekBar scalePicker;
-
     public SharpenAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final SharpenFilter filter = new SharpenFilter();
 
-        scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.GENERIC);
+        ScaleSeekBar scalePicker = factory.createScalePicker(EffectToolFactory.ScaleType.GENERIC);
         scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
 
             @Override
             public void onProgressChanged(float progress, boolean fromUser) {
                 if (fromUser) {
                     filter.setScale(progress);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         scalePicker.setProgress(DEFAULT_SCALE);
 
         filter.setScale(DEFAULT_SCALE);
-        notifyFilterChanged(filter, true);
-    }
-
-    @Override
-    public void doEnd() {
-        scalePicker.setOnScaleChangeListener(null);
+        notifyChanged(filter);
     }
 }
index 42b384d..5fb5ecd 100644 (file)
@@ -29,24 +29,22 @@ public class StraightenAction extends EffectAction {
     private static final float DEFAULT_ANGLE = 0.0f;
     private static final float DEFAULT_ROTATE_SPAN = StraightenFilter.MAX_DEGREES * 2;
 
-    private RotateView rotateView;
-
     public StraightenAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final StraightenFilter filter = new StraightenFilter();
 
-        rotateView = factory.createRotateView();
+        RotateView rotateView = factory.createRotateView();
         rotateView.setOnRotateChangeListener(new RotateView.OnRotateChangeListener() {
 
             @Override
             public void onAngleChanged(float degrees, boolean fromUser){
                 if (fromUser) {
                     filter.setAngle(degrees);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
 
@@ -64,9 +62,4 @@ public class StraightenAction extends EffectAction {
         rotateView.setRotatedAngle(DEFAULT_ANGLE);
         rotateView.setRotateSpan(DEFAULT_ROTATE_SPAN);
     }
-
-    @Override
-    public void doEnd() {
-        rotateView.setOnRotateChangeListener(null);
-    }
 }
index defd2a3..886b172 100644 (file)
@@ -28,35 +28,28 @@ public class TintAction extends EffectAction {
 
     private static final int DEFAULT_COLOR_INDEX = 13;
 
-    private ColorSeekBar colorPicker;
-
     public TintAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final TintFilter filter = new TintFilter();
 
-        colorPicker = factory.createColorPicker();
+        ColorSeekBar colorPicker = factory.createColorPicker();
         colorPicker.setOnColorChangeListener(new ColorSeekBar.OnColorChangeListener() {
 
             @Override
             public void onColorChanged(int color, boolean fromUser) {
                 if (fromUser) {
                     filter.setTint(color);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         // Tint photo with the default color.
         colorPicker.setColorIndex(DEFAULT_COLOR_INDEX);
         filter.setTint(colorPicker.getColor());
-        notifyFilterChanged(filter, true);
-    }
-
-    @Override
-    public void doEnd() {
-        colorPicker.setOnColorChangeListener(null);
+        notifyChanged(filter);
     }
 }
index 0548cc4..d5f311c 100644 (file)
@@ -28,20 +28,6 @@ import android.view.MotionEvent;
 class TouchView extends FullscreenToolView {
 
     /**
-     * Listener of swipes.
-     */
-    public interface SwipeListener {
-
-        void onSwipeLeft();
-
-        void onSwipeRight();
-
-        void onSwipeUp();
-
-        void onSwipeDown();
-    }
-
-    /**
      * Listener of single tap on a point (relative to photo coordinates).
      */
     public interface SingleTapListener {
@@ -50,21 +36,18 @@ class TouchView extends FullscreenToolView {
     }
 
     private final GestureDetector gestureDetector;
-
-    private SwipeListener swipeListener;
     private SingleTapListener singleTapListener;
 
     public TouchView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        final int swipeThreshold = (int) (500 * getResources().getDisplayMetrics().density);
         gestureDetector = new GestureDetector(
                 context, new GestureDetector.SimpleOnGestureListener() {
 
             @Override
             public boolean onDown(MotionEvent e) {
-                // GestureDetector onTouchEvent returns true for fling events only when their
-                // preceding down events are consumed.
+                // GestureDetector onTouchEvent returns true only for events whose preceding
+                // down-events have been consumed.
                 return true;
             }
 
@@ -77,37 +60,10 @@ class TouchView extends FullscreenToolView {
                 }
                 return true;
             }
-
-            @Override
-            public boolean onFling(
-                    MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {
-                if (swipeListener != null) {
-                    float absX = Math.abs(velocityX);
-                    float absY = Math.abs(velocityY);
-                    float deltaX = me2.getX() - me1.getX();
-                    float deltaY = me2.getY() - me1.getY();
-                    int travelX = getWidth() / 4;
-                    int travelY = getHeight() / 4;
-                    if (velocityX > swipeThreshold && absY < absX && deltaX > travelX) {
-                        swipeListener.onSwipeRight();
-                    } else if (velocityX < -swipeThreshold && absY < absX && deltaX < -travelX) {
-                        swipeListener.onSwipeLeft();
-                    } else if (velocityY < -swipeThreshold && absX < absY && deltaY < -travelY) {
-                        swipeListener.onSwipeUp();
-                    } else if (velocityY > swipeThreshold && absX < absY / 2 && deltaY > travelY) {
-                        swipeListener.onSwipeDown();
-                    }
-                }
-                return true;
-            }
         });
         gestureDetector.setIsLongpressEnabled(false);
     }
 
-    public void setSwipeListener(SwipeListener listener) {
-        swipeListener = listener;
-    }
-
     public void setSingleTapListener(SingleTapListener listener) {
         singleTapListener = listener;
     }
index f59c636..fd5121f 100644 (file)
@@ -28,35 +28,28 @@ public class VignetteAction extends EffectAction {
 
     private static final float DEFAULT_SCALE = 0.5f;
 
-    private ScaleSeekBar scalePicker;
-
     public VignetteAction(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void doBegin() {
+    public void prepare() {
         final VignetteFilter filter = new VignetteFilter();
 
-        scalePicker = factory.createScalePicker(EffectToolFactory.ScalePickerType.GENERIC);
+        ScaleSeekBar scalePicker = factory.createScalePicker(EffectToolFactory.ScaleType.GENERIC);
         scalePicker.setOnScaleChangeListener(new ScaleSeekBar.OnScaleChangeListener() {
 
             @Override
             public void onProgressChanged(float progress, boolean fromUser) {
                 if (fromUser) {
                     filter.setScale(progress);
-                    notifyFilterChanged(filter, true);
+                    notifyChanged(filter);
                 }
             }
         });
         scalePicker.setProgress(DEFAULT_SCALE);
 
         filter.setScale(DEFAULT_SCALE);
-        notifyFilterChanged(filter, true);
-    }
-
-    @Override
-    public void doEnd() {
-        scalePicker.setOnScaleChangeListener(null);
+        notifyChanged(filter);
     }
 }
index 727a98c..6376d33 100644 (file)
@@ -30,7 +30,6 @@ public abstract class AbstractScaleFilter extends Filter {
      */
     public void setScale(float scale) {
         this.scale = scale;
-        validate();
     }
 
     @Override
index ccca813..00a6c42 100644 (file)
@@ -37,7 +37,6 @@ public class CropFilter extends Filter {
      */
     public void setCropBounds(RectF bounds) {
         this.bounds = bounds;
-        validate();
     }
 
     @Override
index e82a667..bc233da 100644 (file)
@@ -27,10 +27,6 @@ public class CrossProcessFilter extends Filter {
 
     public static final Creator<CrossProcessFilter> CREATOR = creatorOf(CrossProcessFilter.class);
 
-    public CrossProcessFilter() {
-        validate();
-    }
-
     @Override
     public void process(Photo src, Photo dst) {
         getEffect(EffectFactory.EFFECT_CROSSPROCESS).apply(
index d6f347b..d2e4c7c 100644 (file)
@@ -27,10 +27,6 @@ public class DocumentaryFilter extends Filter {
 
     public static final Creator<DocumentaryFilter> CREATOR = creatorOf(DocumentaryFilter.class);
 
-    public DocumentaryFilter() {
-        validate();
-    }
-
     @Override
     public void process(Photo src, Photo dst) {
         getEffect(EffectFactory.EFFECT_DOCUMENTARY).apply(
index 277e06d..61920d3 100644 (file)
@@ -40,14 +40,6 @@ public class DoodleFilter extends Filter {
 
     private final Vector<Doodle> doodles = new Vector<Doodle>();
 
-    /**
-     * Signals once at least a doodle drawn within photo bounds; this filter is regarded as invalid
-     * (no-op on the photo) until not all its doodling is out of bounds.
-     */
-    public void setDoodledInPhotoBounds() {
-        validate();
-    }
-
     public void addDoodle(Doodle doodle) {
         doodles.add(doodle);
     }
index b94f95e..b2c5525 100644 (file)
@@ -35,7 +35,6 @@ public class DuotoneFilter extends Filter {
     public void setDuotone(int firstColor, int secondColor) {
         this.firstColor = firstColor;
         this.secondColor = secondColor;
-        validate();
     }
 
     @Override
index baa3747..5d1ac22 100644 (file)
@@ -26,8 +26,7 @@ import com.android.gallery3d.photoeditor.Photo;
 import java.util.HashMap;
 
 /**
- * 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.
+ * Image filter for photo editing; all of its methods must be called from a single GL thread.
  */
 public abstract class Filter implements Parcelable {
 
@@ -37,8 +36,6 @@ public abstract class Filter implements Parcelable {
     private static final HashMap<Filter, Effect> effects = new HashMap<Filter, Effect>();
     private static EffectContext context;
 
-    private boolean isValid;
-
     /**
      * Filter context should be released before the current GL context is lost.
      */
@@ -74,18 +71,6 @@ public abstract class Filter implements Parcelable {
         return effect;
     }
 
-    protected void validate() {
-        isValid = true;
-    }
-
-    /**
-     * Some filters, e.g. lighting filters, are initially invalid until set up with parameters while
-     * others, e.g. Sepia or Posterize filters, are initially valid without parameters.
-     */
-    public boolean isValid() {
-        return isValid;
-    }
-
     /**
      * Processes the source bitmap and matrix and output the destination bitmap and matrix.
      *
index 816aad8..9c325c1 100644 (file)
@@ -34,7 +34,6 @@ public class FlipFilter extends Filter {
     public void setFlip(boolean flipHorizontal, boolean flipVertical) {
         flips[0] = flipHorizontal;
         flips[1] = flipVertical;
-        validate();
     }
 
     @Override
index 38dfb52..b0e94ef 100644 (file)
@@ -27,10 +27,6 @@ public class GrayscaleFilter extends Filter {
 
     public static final Creator<GrayscaleFilter> CREATOR = creatorOf(GrayscaleFilter.class);
 
-    public GrayscaleFilter() {
-        validate();
-    }
-
     @Override
     public void process(Photo src, Photo dst) {
         getEffect(EffectFactory.EFFECT_GRAYSCALE).apply(
index f8c5173..16a1d61 100644 (file)
@@ -27,10 +27,6 @@ public class LomoishFilter extends Filter {
 
     public static final Creator<LomoishFilter> CREATOR = creatorOf(LomoishFilter.class);
 
-    public LomoishFilter() {
-        validate();
-    }
-
     @Override
     public void process(Photo src, Photo dst) {
         getEffect(EffectFactory.EFFECT_LOMOISH).apply(
index 88bbd58..db702d7 100644 (file)
@@ -27,10 +27,6 @@ public class NegativeFilter extends Filter {
 
     public static final Creator<NegativeFilter> CREATOR = creatorOf(NegativeFilter.class);
 
-    public NegativeFilter() {
-        validate();
-    }
-
     @Override
     public void process(Photo src, Photo dst) {
         getEffect(EffectFactory.EFFECT_NEGATIVE).apply(
index 186baa9..23e78bf 100644 (file)
@@ -27,10 +27,6 @@ public class PosterizeFilter extends Filter {
 
     public static final Creator<PosterizeFilter> CREATOR = creatorOf(PosterizeFilter.class);
 
-    public PosterizeFilter() {
-        validate();
-    }
-
     @Override
     public void process(Photo src, Photo dst) {
         getEffect(EffectFactory.EFFECT_POSTERIZE).apply(
index 257d322..32e8f7c 100644 (file)
@@ -39,7 +39,6 @@ public class RedEyeFilter extends Filter {
      */
     public void addRedEyePosition(PointF point) {
         redeyes.add(point);
-        validate();
     }
 
     @Override
index d377f96..d820bda 100644 (file)
@@ -31,9 +31,11 @@ public class RotateFilter extends Filter {
 
     private float degrees;
 
+    /**
+     * Sets rotation angle which must be multiples of 90 degrees.
+     */
     public void setAngle(float degrees) {
         this.degrees = degrees;
-        validate();
     }
 
     @Override
index 6c1a70e..d95c0d8 100644 (file)
@@ -27,10 +27,6 @@ public class SepiaFilter extends Filter {
 
     public static final Creator<SepiaFilter> CREATOR = creatorOf(SepiaFilter.class);
 
-    public SepiaFilter() {
-        validate();
-    }
-
     @Override
     public void process(Photo src, Photo dst) {
         getEffect(EffectFactory.EFFECT_SEPIA).apply(
index 90738f0..dffdf50 100644 (file)
@@ -34,7 +34,6 @@ public class StraightenFilter extends Filter {
 
     public void setAngle(float degrees) {
         this.degrees = degrees;
-        validate();
     }
 
     @Override
index af3d777..7a7463e 100644 (file)
@@ -33,7 +33,6 @@ public class TintFilter extends Filter {
 
     public void setTint(int color) {
         this.color = color;
-        validate();
     }
 
     @Override