OSDN Git Service

am 51713de0: am 8141e241: Merge "Improves UI / size" into gb-ub-photos-carlsbad
authornicolasroard <nicolasroard@google.com>
Tue, 27 Aug 2013 16:53:24 +0000 (09:53 -0700)
committerAndroid Git Automerger <android-git-automerger@android.com>
Tue, 27 Aug 2013 16:53:24 +0000 (09:53 -0700)
* commit '51713de0b3710ca90bc1d3b454cbdcee482b22dc':
  Improves UI / size

21 files changed:
res/drawable-nodpi/geometry_shadow.9.png
res/drawable-nodpi/spot_mask.png [new file with mode: 0644]
res/layout-land/filtershow_activity.xml
res/layout/filtershow_activity.xml
res/values/styles.xml
src/com/android/gallery3d/filtershow/EditorPlaceHolder.java
src/com/android/gallery3d/filtershow/FilterShowActivity.java
src/com/android/gallery3d/filtershow/cache/BitmapCache.java
src/com/android/gallery3d/filtershow/category/CategorySelected.java [new file with mode: 0644]
src/com/android/gallery3d/filtershow/category/CategoryView.java
src/com/android/gallery3d/filtershow/editors/Editor.java
src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java
src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java
src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java
src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java
src/com/android/gallery3d/filtershow/pipeline/FilterEnvironment.java
src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java
src/com/android/gallery3d/filtershow/pipeline/RenderingRequestTask.java

index 2f7abdc..205e931 100644 (file)
Binary files a/res/drawable-nodpi/geometry_shadow.9.png and b/res/drawable-nodpi/geometry_shadow.9.png differ
diff --git a/res/drawable-nodpi/spot_mask.png b/res/drawable-nodpi/spot_mask.png
new file mode 100644 (file)
index 0000000..8953759
Binary files /dev/null and b/res/drawable-nodpi/spot_mask.png differ
index e6599f0..72bbdea 100644 (file)
 
     </LinearLayout>
 
+    <com.android.gallery3d.filtershow.category.CategorySelected
+            android:layout_width="@dimen/category_panel_icon_size"
+            android:layout_height="@dimen/category_panel_icon_size"
+            android:id="@+id/categorySelectedIndicator"
+            android:visibility="invisible"/>
+
 </FrameLayout>
index c580f19..aabdb73 100644 (file)
 
     </LinearLayout>
 
+    <com.android.gallery3d.filtershow.category.CategorySelected
+            android:layout_width="@dimen/category_panel_icon_size"
+            android:layout_height="@dimen/category_panel_icon_size"
+            android:id="@+id/categorySelectedIndicator"
+            android:visibility="invisible"/>
+
 </FrameLayout>
index 67c53f8..58c87ce 100644 (file)
@@ -29,7 +29,7 @@
         <item name="android:colorBackgroundCacheHint">@null</item>
     </style>
     <style name="Theme.FilterShow" parent="Theme.Gallery">
-        <item name="android:windowBackground">@color/background_screen</item>
+        <item name="android:windowBackground">@null</item>
     </style>
     <style name="Holo.ActionBar" parent="android:Widget.Holo.ActionBar">
         <item name="android:displayOptions">useLogo|showHome</item>
index 95abce1..95fc56d 100644 (file)
@@ -45,7 +45,7 @@ public class EditorPlaceHolder {
         }
 
         editor.createEditor(mActivity, mContainer);
-        editor.getImageShow().bindAsImageLoadListener();
+        editor.getImageShow().attach();
         mContainer.setVisibility(View.VISIBLE);
         mContainer.removeAllViews();
         View eview = editor.getTopLevelView();
index c3a5e15..c7e9cc6 100644 (file)
@@ -32,6 +32,7 @@ import android.graphics.Bitmap;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -66,6 +67,7 @@ import com.android.gallery3d.data.LocalAlbum;
 import com.android.gallery3d.filtershow.cache.ImageLoader;
 import com.android.gallery3d.filtershow.category.Action;
 import com.android.gallery3d.filtershow.category.CategoryAdapter;
+import com.android.gallery3d.filtershow.category.CategorySelected;
 import com.android.gallery3d.filtershow.category.CategoryView;
 import com.android.gallery3d.filtershow.category.MainPanel;
 import com.android.gallery3d.filtershow.category.SwipableView;
@@ -136,6 +138,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
     private View mSaveButton = null;
 
     private EditorPlaceHolder mEditorPlaceHolder = new EditorPlaceHolder(this);
+    private Editor mCurrentEditor = null;
 
     private static final int SELECT_PICTURE = 1;
     private static final String LOGTAG = "FilterShowActivity";
@@ -364,6 +367,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
         ActionBar actionBar = getActionBar();
         actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
         actionBar.setCustomView(R.layout.filtershow_actionbar);
+        actionBar.setBackgroundDrawable(new ColorDrawable(
+                getResources().getColor(R.color.background_screen)));
 
         mSaveButton = actionBar.getCustomView();
         mSaveButton.setOnClickListener(new OnClickListener() {
@@ -600,6 +605,11 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
             && MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) {
             return;
         }
+        if (filterRepresentation instanceof FilterUserPresetRepresentation
+                || filterRepresentation instanceof FilterRotateRepresentation
+                || filterRepresentation instanceof FilterMirrorRepresentation) {
+            MasterImage.getImage().onNewLook(filterRepresentation);
+        }
         ImagePreset oldPreset = MasterImage.getImage().getPreset();
         ImagePreset copy = new ImagePreset(oldPreset);
         FilterRepresentation representation = copy.getRepresentation(filterRepresentation);
@@ -639,7 +649,10 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
         useFilterRepresentation(representation);
 
         // show representation
-        Editor mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId());
+        if (mCurrentEditor != null) {
+            mCurrentEditor.detach();
+        }
+        mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId());
         loadEditorPanel(representation, mCurrentEditor);
         hideInformationPanel();
     }
@@ -1358,4 +1371,27 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
         }
         return super.dispatchTouchEvent(ev);
     }
+
+    public void startTouchAnimation(View target, float x, float y) {
+        final CategorySelected hint =
+                (CategorySelected) findViewById(R.id.categorySelectedIndicator);
+        int location[] = new int[2];
+        target.getLocationOnScreen(location);
+        int locationHint[] = new int[2];
+        ((View)hint.getParent()).getLocationOnScreen(locationHint);
+        int dx = (int) (x - (hint.getWidth())/2);
+        int dy = (int) (y - (hint.getHeight())/2);
+        hint.setTranslationX(location[0] - locationHint[0] + dx);
+        hint.setTranslationY(location[1] - locationHint[1] + dy);
+        hint.setVisibility(View.VISIBLE);
+        hint.animate().scaleX(2).scaleY(2).alpha(0).withEndAction(new Runnable() {
+            @Override
+            public void run() {
+                hint.setVisibility(View.INVISIBLE);
+                hint.setScaleX(1);
+                hint.setScaleY(1);
+                hint.setAlpha(1);
+            }
+        });
+    }
 }
index 2699878..339ddf0 100644 (file)
@@ -75,7 +75,7 @@ public class BitmapCache {
 
     public synchronized Bitmap getBitmap(int w, int h) {
         Long key = calcKey(w, h);
-        WeakReference<Bitmap> ref = null; //mBitmapCache.remove(key);
+        WeakReference<Bitmap> ref = null;
         ArrayList<WeakReference<Bitmap>> list = mBitmapCache.get(key);
         if (list != null && list.size() > 0) {
             ref = list.remove(0);
diff --git a/src/com/android/gallery3d/filtershow/category/CategorySelected.java b/src/com/android/gallery3d/filtershow/category/CategorySelected.java
new file mode 100644 (file)
index 0000000..1a6135b
--- /dev/null
@@ -0,0 +1,27 @@
+package com.android.gallery3d.filtershow.category;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class CategorySelected extends View {
+    Paint mPaint = new Paint();
+
+    public CategorySelected(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void onDraw(Canvas canvas) {
+        mPaint.reset();
+        int margin = 20;
+        mPaint.setStrokeWidth(margin);
+        mPaint.setAntiAlias(true);
+        mPaint.setStyle(Paint.Style.STROKE);
+        mPaint.setColor(Color.GRAY);
+        canvas.drawCircle(getWidth()/2, getHeight()/2, getWidth()/2 - margin, mPaint);
+    }
+
+}
index 3a9d473..c613c21 100644 (file)
@@ -154,6 +154,11 @@ public class CategoryView extends IconView
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         boolean ret = super.onTouchEvent(event);
+        FilterShowActivity activity = (FilterShowActivity) getContext();
+
+        if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+            activity.startTouchAnimation(this, event.getX(), event.getY());
+        }
         if (!canBeRemoved()) {
             return ret;
         }
@@ -171,7 +176,6 @@ public class CategoryView extends IconView
                 delta = event.getX() - mStartTouchX;
             }
             if (Math.abs(delta) > mDeleteSlope) {
-                FilterShowActivity activity = (FilterShowActivity) getContext();
                 activity.setHandlesSwipeForView(this, mStartTouchX, mStartTouchY);
             }
         }
index fb04fb3..5f8e8f6 100644 (file)
@@ -323,5 +323,8 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
     }
 
     public void detach() {
+        if (mImageShow != null) {
+            mImageShow.detach();
+        }
     }
 }
index 765796e..84caa9e 100644 (file)
@@ -23,8 +23,12 @@ import android.util.Log;
 import com.android.gallery3d.R;
 import com.android.gallery3d.filtershow.editors.EditorMirror;
 import com.android.gallery3d.filtershow.editors.ImageOnlyEditor;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
+import com.android.gallery3d.filtershow.pipeline.ImagePreset;
 
 import java.io.IOException;
+import java.util.ArrayList;
 
 public class FilterMirrorRepresentation extends FilterRepresentation {
     public static final String SERIALIZATION_NAME = "MIRROR";
@@ -108,18 +112,34 @@ public class FilterMirrorRepresentation extends FilterRepresentation {
         mMirror = mirror;
     }
 
+    public boolean isHorizontal() {
+        if (mMirror == Mirror.BOTH
+                || mMirror == Mirror.HORIZONTAL) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isVertical() {
+        if (mMirror == Mirror.BOTH
+                || mMirror == Mirror.VERTICAL) {
+            return true;
+        }
+        return false;
+    }
+
     public void cycle() {
         switch (mMirror) {
             case NONE:
                 mMirror = Mirror.HORIZONTAL;
                 break;
             case HORIZONTAL:
-                mMirror = Mirror.VERTICAL;
-                break;
-            case VERTICAL:
                 mMirror = Mirror.BOTH;
                 break;
             case BOTH:
+                mMirror = Mirror.VERTICAL;
+                break;
+            case VERTICAL:
                 mMirror = Mirror.NONE;
                 break;
         }
index 1cefe08..e3cd56d 100644 (file)
@@ -23,6 +23,7 @@ import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.RectF;
 
+import com.android.gallery3d.filtershow.cache.BitmapCache;
 import com.android.gallery3d.filtershow.cache.ImageLoader;
 import com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
 import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
@@ -209,7 +210,19 @@ public final class GeometryMathUtils {
         return q;
     }
 
-    private static void concatMirrorMatrix(Matrix m, Mirror type) {
+    private static void concatMirrorMatrix(Matrix m, GeometryHolder holder) {
+        Mirror type = holder.mirror;
+        if (type == Mirror.HORIZONTAL) {
+            if (holder.rotation.value() == 90
+                    || holder.rotation.value() == 270) {
+                type = Mirror.VERTICAL;
+            }
+        } else if (type == Mirror.VERTICAL) {
+            if (holder.rotation.value() == 90
+                    || holder.rotation.value() == 270) {
+                type = Mirror.HORIZONTAL;
+            }
+        }
         if (type == Mirror.HORIZONTAL) {
             m.postScale(-1, 1);
         } else if (type == Mirror.VERTICAL) {
@@ -299,7 +312,8 @@ public final class GeometryMathUtils {
         crop.roundOut(frame);
         Matrix m = getCropSelectionToScreenMatrix(null, holder, width, height, frame.width(),
                 frame.height());
-        Bitmap temp = Bitmap.createBitmap(frame.width(), frame.height(), Bitmap.Config.ARGB_8888);
+        BitmapCache bitmapCache = MasterImage.getImage().getBitmapCache();
+        Bitmap temp = bitmapCache.getBitmap(frame.width(), frame.height());
         Canvas canvas = new Canvas(temp);
         Paint paint = new Paint();
         paint.setAntiAlias(true);
@@ -345,7 +359,7 @@ public final class GeometryMathUtils {
         compensation.postRotate(angle, cx, cy);
         compensation.postRotate(rotation, cx, cy);
         compensation.postTranslate(-cx, -cy);
-        concatMirrorMatrix(compensation, holder.mirror);
+        concatMirrorMatrix(compensation, holder);
         compensation.postTranslate(cx, cy);
         return compensation;
     }
@@ -371,6 +385,10 @@ public final class GeometryMathUtils {
         // If there are geometry changes, apply them to the image
         if (!holder.isNil()) {
             bmap = applyFullGeometryMatrix(bmap, holder);
+            if (bmap != image) {
+                BitmapCache cache = MasterImage.getImage().getBitmapCache();
+                cache.cache(image);
+            }
         }
         return bmap;
     }
@@ -410,7 +428,7 @@ public final class GeometryMathUtils {
         Matrix m = new Matrix();
         m.setTranslate(-centerX, -centerY);
         m.postRotate(holder.straighten + holder.rotation.value());
-        concatMirrorMatrix(m, holder.mirror);
+        concatMirrorMatrix(m, holder);
         return m;
     }
 
index 2bb269e..ad45687 100644 (file)
@@ -19,13 +19,15 @@ package com.android.gallery3d.filtershow.imageshow;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.RectF;
+import android.graphics.Shader;
 import android.graphics.drawable.NinePatchDrawable;
 import android.util.AttributeSet;
 import android.view.GestureDetector;
@@ -38,12 +40,14 @@ import android.widget.LinearLayout;
 
 import com.android.gallery3d.R;
 import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
 import com.android.gallery3d.filtershow.filters.ImageFilter;
 import com.android.gallery3d.filtershow.pipeline.ImagePreset;
 import com.android.gallery3d.filtershow.tools.SaveImage;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.Collection;
 
 public class ImageShow extends View implements OnGestureListener,
@@ -74,6 +78,7 @@ public class ImageShow extends View implements OnGestureListener,
     private NinePatchDrawable mShadow = null;
     private Rect mShadowBounds = new Rect();
     private int mShadowMargin = 15; // not scaled, fixed in the asset
+    private boolean mShadowDrawn = false;
 
     private Point mTouchDown = new Point();
     private Point mTouch = new Point();
@@ -93,6 +98,21 @@ public class ImageShow extends View implements OnGestureListener,
     }
     InteractionMode mInteractionMode = InteractionMode.NONE;
 
+    private static Bitmap sMask;
+    private Paint mMaskPaint = new Paint();
+    private Matrix mShaderMatrix = new Matrix();
+
+    private static Bitmap convertToAlphaMask(Bitmap b) {
+        Bitmap a = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ALPHA_8);
+        Canvas c = new Canvas(a);
+        c.drawBitmap(b, 0.0f, 0.0f, null);
+        return a;
+    }
+
+    private static Shader createShader(Bitmap b) {
+        return new BitmapShader(b, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+    }
+
     private FilterShowActivity mActivity = null;
 
     public FilterShowActivity getActivity() {
@@ -138,7 +158,20 @@ public class ImageShow extends View implements OnGestureListener,
         mShadow = (NinePatchDrawable) res.getDrawable(R.drawable.geometry_shadow);
         setupGestureDetector(context);
         mActivity = (FilterShowActivity) context;
+        if (sMask == null) {
+            Bitmap mask = BitmapFactory.decodeResource(res, R.drawable.spot_mask);
+            sMask = convertToAlphaMask(mask);
+        }
+    }
+
+    public void attach() {
         MasterImage.getImage().addObserver(this);
+        bindAsImageLoadListener();
+    }
+
+    public void detach() {
+        MasterImage.getImage().removeObserver(this);
+        mMaskPaint.reset();
     }
 
     public void setupGestureDetector(Context context) {
@@ -206,36 +239,27 @@ public class ImageShow extends View implements OnGestureListener,
         float scaleFactor = MasterImage.getImage().getScaleFactor();
         Point translation = MasterImage.getImage().getTranslation();
 
-        Matrix scalingMatrix = new Matrix();
-        scalingMatrix.postScale(scaleFactor, scaleFactor, cx, cy);
-        scalingMatrix.preTranslate(translation.x, translation.y);
-
-        RectF unscaledClipRect = new RectF(mImageBounds);
-        scalingMatrix.mapRect(unscaledClipRect, unscaledClipRect);
-
         canvas.save();
 
-        boolean enablePartialRendering = false;
-
-        // For now, partial rendering is disabled for all filters,
-        // so no need to clip.
-        if (enablePartialRendering && !unscaledClipRect.isEmpty()) {
-            canvas.clipRect(unscaledClipRect);
-        }
+        mShadowDrawn = false;
 
         canvas.save();
         // TODO: center scale on gesture
         canvas.scale(scaleFactor, scaleFactor, cx, cy);
         canvas.translate(translation.x, translation.y);
-        drawImage(canvas, getFilteredImage(), true);
         Bitmap highresPreview = MasterImage.getImage().getHighresImage();
-        if (highresPreview != null) {
+
+        boolean isDoingNewLookAnimation = MasterImage.getImage().onGoingNewLookAnimation();
+
+        if (!isDoingNewLookAnimation && highresPreview != null) {
             drawImage(canvas, highresPreview, true);
+        } else {
+            drawImage(canvas, getFilteredImage(), true);
         }
         canvas.restore();
 
         Bitmap partialPreview = MasterImage.getImage().getPartialImage();
-        if (partialPreview != null) {
+        if (!isDoingNewLookAnimation && partialPreview != null) {
             canvas.save();
             Rect originalBounds = MasterImage.getImage().getOriginalBounds();
             Collection<FilterRepresentation> geo = MasterImage.getImage().getPreset()
@@ -274,30 +298,135 @@ public class ImageShow extends View implements OnGestureListener,
     }
 
     public void drawImage(Canvas canvas, Bitmap image, boolean updateBounds) {
-        if (image != null) {
-            Rect s = new Rect(0, 0, image.getWidth(),
-                    image.getHeight());
-
-            float scale = GeometryMathUtils.scale(image.getWidth(), image.getHeight(), getWidth(),
-                    getHeight());
-
-            float w = image.getWidth() * scale;
-            float h = image.getHeight() * scale;
-            float ty = (getHeight() - h) / 2.0f;
-            float tx = (getWidth() - w) / 2.0f;
-
-            Rect d = new Rect((int) tx + mShadowMargin,
-                    (int) ty + mShadowMargin,
-                    (int) (w + tx) - mShadowMargin,
-                    (int) (h + ty) - mShadowMargin);
-            if (updateBounds) {
-                mImageBounds = d;
+        if (image == null) {
+            return;
+        }
+
+        Rect d = computeImageBounds(image);
+
+        if (updateBounds) {
+            mImageBounds = d;
+        }
+
+        float centerX = mShadowMargin + (getWidth() - 2 * mShadowMargin) / 2;
+        float centerY = mShadowMargin + (getHeight() - 2 * mShadowMargin) / 2;
+
+        MasterImage master = MasterImage.getImage();
+        canvas.save();
+        if (master.onGoingNewLookAnimation()) {
+            if (master.getCurrentLookAnimation()
+                    == MasterImage.CIRCLE_ANIMATION
+                    && MasterImage.getImage().getPreviousImage() != null) {
+                float maskScale = MasterImage.getImage().getMaskScale();
+                if (maskScale > 1.0f) {
+                    float maskW = sMask.getWidth() / 2.0f;
+                    float maskH = sMask.getHeight() / 2.0f;
+                    float x = centerX - maskW * maskScale;
+                    float y = centerY - maskH * maskScale;
+
+                    // Prepare the shader
+                    mShaderMatrix.reset();
+                    mShaderMatrix.setScale(1.0f / maskScale, 1.0f / maskScale);
+                    mShaderMatrix.preTranslate(-x + d.left, -y + d.top);
+                    float scaleImageX = d.width() / (float) image.getWidth();
+                    float scaleImageY = d.height() / (float) image.getHeight();
+                    mShaderMatrix.preScale(scaleImageX, scaleImageY);
+                    mMaskPaint.reset();
+                    mMaskPaint.setShader(createShader(image));
+                    mMaskPaint.getShader().setLocalMatrix(mShaderMatrix);
+
+                    drawImage(canvas, MasterImage.getImage().getPreviousImage());
+                    canvas.translate(x, y);
+                    canvas.scale(maskScale, maskScale);
+                    canvas.drawBitmap(sMask, 0, 0, mMaskPaint);
+                } else {
+                    drawImage(canvas, image);
+                }
+            } else if (master.getCurrentLookAnimation()
+                    == MasterImage.ROTATE_ANIMATION) {
+                Rect d2 = computeImageBounds(master.getPreviousImage());
+                float finalScale = d.width() / (float) d2.height();
+                finalScale = (1.0f * (1.0f - master.getAnimFraction()))
+                        + (finalScale * master.getAnimFraction());
+                canvas.rotate(master.getAnimRotationValue(), centerX, centerY);
+                canvas.scale(finalScale, finalScale, centerX, centerY);
+                drawImage(canvas, master.getPreviousImage());
+            } else if (master.getCurrentLookAnimation()
+                    == MasterImage.MIRROR_ANIMATION) {
+                if (master.getCurrentFilterRepresentation()
+                        instanceof FilterMirrorRepresentation) {
+                    FilterMirrorRepresentation rep =
+                            (FilterMirrorRepresentation) master.getCurrentFilterRepresentation();
+
+                    ImagePreset preset = master.getPreset();
+                    ArrayList<FilterRepresentation> geometry =
+                            (ArrayList<FilterRepresentation>) preset.getGeometryFilters();
+                    GeometryMathUtils.GeometryHolder holder = null;
+                    holder = GeometryMathUtils.unpackGeometry(geometry);
+
+                    if (holder.rotation.value() == 90 || holder.rotation.value() == 270) {
+                        if (rep.isHorizontal() && !rep.isVertical()) {
+                            canvas.scale(1, master.getAnimRotationValue(), centerX, centerY);
+                        } else if (rep.isVertical() && !rep.isHorizontal()) {
+                            canvas.scale(1, master.getAnimRotationValue(), centerX, centerY);
+                        } else if (rep.isHorizontal() && rep.isVertical()) {
+                            canvas.scale(master.getAnimRotationValue(), 1, centerX, centerY);
+                        } else {
+                            canvas.scale(master.getAnimRotationValue(), 1, centerX, centerY);
+                        }
+                    } else {
+                        if (rep.isHorizontal() && !rep.isVertical()) {
+                            canvas.scale(master.getAnimRotationValue(), 1, centerX, centerY);
+                        } else if (rep.isVertical() && !rep.isHorizontal()) {
+                            canvas.scale(master.getAnimRotationValue(), 1, centerX, centerY);
+                        } else  if (rep.isHorizontal() && rep.isVertical()) {
+                            canvas.scale(1, master.getAnimRotationValue(), centerX, centerY);
+                        } else {
+                            canvas.scale(1, master.getAnimRotationValue(), centerX, centerY);
+                        }
+                    }
+                }
+                drawImage(canvas, master.getPreviousImage());
             }
+        } else {
+            drawImage(canvas, image);
+        }
+        canvas.restore();
+    }
+
+    private void drawImage(Canvas canvas, Bitmap image) {
+        Rect d = computeImageBounds(image);
+        float scaleImageX = d.width() / (float) image.getWidth();
+        float scaleImageY = d.height() / (float) image.getHeight();
+        Matrix imageMatrix = new Matrix();
+        imageMatrix.postScale(scaleImageX, scaleImageY);
+        imageMatrix.postTranslate(d.left, d.top);
+        drawShadow(canvas, d);
+        canvas.clipRect(d);
+        canvas.drawBitmap(image, imageMatrix, mPaint);
+    }
+
+    private Rect computeImageBounds(Bitmap image) {
+        float scale = GeometryMathUtils.scale(image.getWidth(), image.getHeight(),
+                getWidth(), getHeight());
+
+        float w = image.getWidth() * scale;
+        float h = image.getHeight() * scale;
+        float ty = (getHeight() - h) / 2.0f;
+        float tx = (getWidth() - w) / 2.0f;
+        return new Rect((int) tx + mShadowMargin,
+                (int) ty + mShadowMargin,
+                (int) (w + tx) - mShadowMargin,
+                (int) (h + ty) - mShadowMargin);
+    }
+
+    private void drawShadow(Canvas canvas, Rect d) {
+        if (!mShadowDrawn) {
             mShadowBounds.set(d.left - mShadowMargin, d.top - mShadowMargin,
                     d.right + mShadowMargin, d.bottom + mShadowMargin);
             mShadow.setBounds(mShadowBounds);
             mShadow.draw(canvas);
-            canvas.drawBitmap(image, s, d, mPaint);
+            mShadowDrawn = true;
         }
     }
 
index fabc7b3..525b458 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.gallery3d.filtershow.imageshow;
 
+import android.animation.Animator;
+import android.animation.ValueAnimator;
 import android.graphics.Bitmap;
 import android.graphics.Matrix;
 import android.graphics.Point;
@@ -24,12 +26,16 @@ import android.graphics.RectF;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
+import android.util.Log;
 
 import com.android.gallery3d.exif.ExifTag;
 import com.android.gallery3d.filtershow.FilterShowActivity;
 import com.android.gallery3d.filtershow.cache.BitmapCache;
 import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
 import com.android.gallery3d.filtershow.filters.ImageFilter;
 import com.android.gallery3d.filtershow.history.HistoryItem;
 import com.android.gallery3d.filtershow.history.HistoryManager;
@@ -77,6 +83,16 @@ public class MasterImage implements RenderingRequestCaller {
     private Bitmap mFiltersOnlyBitmap = null;
     private Bitmap mPartialBitmap = null;
     private Bitmap mHighresBitmap = null;
+    private Bitmap mPreviousImage = null;
+
+    private float mMaskScale = 1;
+    private boolean mOnGoingNewLookAnimation = false;
+    private float mAnimRotationValue = 0;
+    private float mAnimFraction = 0;
+    private int mCurrentLookAnimation = 0;
+    public static final int CIRCLE_ANIMATION = 1;
+    public static final int ROTATE_ANIMATION = 2;
+    public static final int MIRROR_ANIMATION = 3;
 
     private HistoryManager mHistory = null;
     private StateAdapter mState = null;
@@ -205,6 +221,10 @@ public class MasterImage implements RenderingRequestCaller {
         mObservers.add(observer);
     }
 
+    public void removeObserver(ImageShow observer) {
+        mObservers.remove(observer);
+    }
+
     public void setActivity(FilterShowActivity activity) {
         mActivity = activity;
     }
@@ -328,6 +348,103 @@ public class MasterImage implements RenderingRequestCaller {
         return mHighresBitmap;
     }
 
+    public Bitmap getPreviousImage() {
+        return mPreviousImage;
+    }
+
+    public float getMaskScale() {
+        return mMaskScale;
+    }
+
+    public void setMaskScale(float scale) {
+        mMaskScale = scale;
+        notifyObservers();
+    }
+
+    public float getAnimRotationValue() {
+        return mAnimRotationValue;
+    }
+
+    public void setAnimRotation(float rotation) {
+        mAnimRotationValue = rotation;
+        notifyObservers();
+    }
+
+    public void setAnimFraction(float fraction) {
+        mAnimFraction = fraction;
+    }
+
+    public float getAnimFraction() {
+        return mAnimFraction;
+    }
+
+    public boolean onGoingNewLookAnimation() {
+        return mOnGoingNewLookAnimation;
+    }
+
+    public int getCurrentLookAnimation() {
+        return mCurrentLookAnimation;
+    }
+
+    public void onNewLook(FilterRepresentation newRepresentation) {
+        getBitmapCache().cache(mPreviousImage);
+        mPreviousImage = getBitmapCache().getBitmapCopy(getFilteredImage());
+        ValueAnimator animator = null;
+        if (newRepresentation instanceof FilterUserPresetRepresentation) {
+            mCurrentLookAnimation = CIRCLE_ANIMATION;
+            animator = ValueAnimator.ofFloat(1, 20);
+        }
+        if (newRepresentation instanceof FilterRotateRepresentation) {
+            mCurrentLookAnimation = ROTATE_ANIMATION;
+            animator = ValueAnimator.ofFloat(0, 90);
+        }
+        if (newRepresentation instanceof FilterMirrorRepresentation) {
+            mCurrentLookAnimation = MIRROR_ANIMATION;
+            animator = ValueAnimator.ofFloat(1, 0, -1);
+        }
+        animator.setDuration(400);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                if (mCurrentLookAnimation == CIRCLE_ANIMATION) {
+                    Log.v(LOGTAG, "circle animation " + animation.getAnimatedValue());
+                    setMaskScale((Float) animation.getAnimatedValue());
+                } else if (mCurrentLookAnimation == ROTATE_ANIMATION
+                        || mCurrentLookAnimation == MIRROR_ANIMATION) {
+                    setAnimRotation((Float) animation.getAnimatedValue());
+                    setAnimFraction(animation.getAnimatedFraction());
+                }
+            }
+        });
+        animator.addListener(new Animator.AnimatorListener() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mOnGoingNewLookAnimation = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mBitmapCache.cache(mPreviousImage);
+                mPreviousImage = null;
+                mOnGoingNewLookAnimation = false;
+                setMaskScale(1);
+                setAnimRotation(0);
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+
+            }
+
+            @Override
+            public void onAnimationRepeat(Animator animation) {
+
+            }
+        });
+        animator.start();
+        notifyObservers();
+    }
+
     public void notifyObservers() {
         for (ImageShow observer : mObservers) {
             observer.invalidate();
@@ -339,9 +456,9 @@ public class MasterImage implements RenderingRequestCaller {
         newPresetGeometryOnly.setDoApplyFilters(false);
         newPresetGeometryOnly.setDoApplyGeometry(true);
         if (force || mGeometryOnlyPreset == null
-                || !newPresetGeometryOnly.same(mGeometryOnlyPreset)) {
+                || !newPresetGeometryOnly.equals(mGeometryOnlyPreset)) {
             mGeometryOnlyPreset = newPresetGeometryOnly;
-            RenderingRequest.post(mActivity, getOriginalBitmapLarge(),
+            RenderingRequest.post(mActivity, null,
                     mGeometryOnlyPreset, RenderingRequest.GEOMETRY_RENDERING, this);
         }
         ImagePreset newPresetFiltersOnly = new ImagePreset(mPreset);
@@ -350,7 +467,7 @@ public class MasterImage implements RenderingRequestCaller {
         if (force || mFiltersOnlyPreset == null
                 || !newPresetFiltersOnly.same(mFiltersOnlyPreset)) {
             mFiltersOnlyPreset = newPresetFiltersOnly;
-            RenderingRequest.post(mActivity, MasterImage.getImage().getOriginalBitmapLarge(),
+            RenderingRequest.post(mActivity, null,
                     mFiltersOnlyPreset, RenderingRequest.FILTERS_RENDERING, this);
         }
     }
@@ -474,10 +591,12 @@ public class MasterImage implements RenderingRequestCaller {
 
         boolean needsCheckModification = false;
         if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
+            mBitmapCache.cache(mGeometryOnlyBitmap);
             mGeometryOnlyBitmap = request.getBitmap();
             needsCheckModification = true;
         }
         if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
+            mBitmapCache.cache(mFiltersOnlyBitmap);
             mFiltersOnlyBitmap = request.getBitmap();
             notifyObservers();
             needsCheckModification = true;
index 8f6eda2..2a83219 100644 (file)
@@ -170,9 +170,11 @@ public class CacheProcessing {
                     + mSteps.size() + " cacheBitmap: " + cacheBitmap);
         }
 
+        Bitmap originalCopy = null;
         for (int i = findBaseImageIndex; i < mSteps.size(); i++) {
             if (i == -1 || cacheBitmap == null) {
                 cacheBitmap = environment.getBitmapCopy(originalBitmap);
+                originalCopy = cacheBitmap;
                 if (DEBUG) {
                     Log.v(LOGTAG, "i: " + i + " cacheBitmap: " + cacheBitmap + " w: "
                             + cacheBitmap.getWidth() + " h: " + cacheBitmap.getHeight()
@@ -189,12 +191,12 @@ public class CacheProcessing {
                     Log.v(LOGTAG, "i: " + i + " get new copy for cacheBitmap "
                             + cacheBitmap + " apply...");
                 }
-                environment.cache(step.cache);
                 cacheBitmap = environment.getBitmapCopy(cacheBitmap);
                 cacheBitmap = step.apply(environment, cacheBitmap);
                 step.cache = cacheBitmap;
             }
         }
+        environment.cache(originalCopy);
 
         if (DEBUG) {
             Log.v(LOGTAG, "now let's cleanup the cache...");
index 0ff8bfb..823da64 100644 (file)
@@ -221,18 +221,64 @@ public class CachingPipeline implements PipelineInterface {
             Bitmap bmp = preset.apply(bitmap, mEnvironment);
             if (!mEnvironment.needsStop()) {
                 request.setBitmap(bmp);
+            } else {
+                mEnvironment.cache(bmp);
+            }
+            mFiltersManager.freeFilterResources(preset);
+        }
+    }
+
+    public void renderGeometry(RenderingRequest request) {
+        synchronized (CachingPipeline.class) {
+            if (getRenderScriptContext() == null) {
+                return;
+            }
+            ImagePreset preset = request.getImagePreset();
+            setupEnvironment(preset, false);
+            Bitmap bitmap = MasterImage.getImage().getOriginalBitmapHighres();
+            if (bitmap == null) {
+                return;
+            }
+            bitmap = mEnvironment.getBitmapCopy(bitmap);
+            bitmap = preset.applyGeometry(bitmap, mEnvironment);
+            if (!mEnvironment.needsStop()) {
+                request.setBitmap(bitmap);
+            } else {
+                mEnvironment.cache(bitmap);
+            }
+            mFiltersManager.freeFilterResources(preset);
+        }
+    }
+
+    public void renderFilters(RenderingRequest request) {
+        synchronized (CachingPipeline.class) {
+            if (getRenderScriptContext() == null) {
+                return;
+            }
+            ImagePreset preset = request.getImagePreset();
+            setupEnvironment(preset, false);
+            Bitmap bitmap = MasterImage.getImage().getOriginalBitmapHighres();
+            if (bitmap == null) {
+                return;
+            }
+            bitmap = mEnvironment.getBitmapCopy(bitmap);
+            bitmap = preset.apply(bitmap, mEnvironment);
+            if (!mEnvironment.needsStop()) {
+                request.setBitmap(bitmap);
+            } else {
+                mEnvironment.cache(bitmap);
             }
             mFiltersManager.freeFilterResources(preset);
         }
     }
 
     public synchronized void render(RenderingRequest request) {
+        // TODO: cleanup/remove GEOMETRY / FILTERS paths
         synchronized (CachingPipeline.class) {
             if (getRenderScriptContext() == null) {
                 return;
             }
-            if (((request.getType() != RenderingRequest.PARTIAL_RENDERING
-                    && request.getType() != RenderingRequest.HIGHRES_RENDERING)
+            if (((request.getType() != RenderingRequest.PARTIAL_RENDERING)
                     && request.getBitmap() == null)
                     || request.getImagePreset() == null) {
                 return;
@@ -244,8 +290,7 @@ public class CachingPipeline implements PipelineInterface {
 
             Bitmap bitmap = request.getBitmap();
             ImagePreset preset = request.getImagePreset();
-            setupEnvironment(preset,
-                    request.getType() != RenderingRequest.HIGHRES_RENDERING);
+            setupEnvironment(preset, true);
             mFiltersManager.freeFilterResources(preset);
 
             if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
@@ -260,13 +305,6 @@ public class CachingPipeline implements PipelineInterface {
                 }
             }
 
-            if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
-                bitmap = MasterImage.getImage().getOriginalBitmapHighres();
-                if (bitmap != null) {
-                    bitmap = preset.applyGeometry(bitmap, mEnvironment);
-                }
-            }
-
             if (request.getType() == RenderingRequest.FULL_RENDERING
                     || request.getType() == RenderingRequest.GEOMETRY_RENDERING
                     || request.getType() == RenderingRequest.FILTERS_RENDERING) {
@@ -290,7 +328,6 @@ public class CachingPipeline implements PipelineInterface {
                     || request.getType() == RenderingRequest.FILTERS_RENDERING
                     || request.getType() == RenderingRequest.ICON_RENDERING
                     || request.getType() == RenderingRequest.PARTIAL_RENDERING
-                    || request.getType() == RenderingRequest.HIGHRES_RENDERING
                     || request.getType() == RenderingRequest.STYLE_ICON_RENDERING) {
 
                 if (request.getType() == RenderingRequest.ICON_RENDERING) {
@@ -351,6 +388,7 @@ public class CachingPipeline implements PipelineInterface {
         Vector<FilterRepresentation> filters = preset.getFilters();
         Bitmap result = mCachedProcessing.process(mOriginalBitmap, filters, mEnvironment);
         buffer.setProducer(result);
+        mEnvironment.cache(result);
     }
 
     public synchronized void computeOld(SharedBuffer buffer, ImagePreset preset, int type) {
index b345376..72c02f3 100644 (file)
@@ -133,6 +133,9 @@ public class FilterEnvironment {
         filter.useRepresentation(representation);
         filter.setEnvironment(this);
         Bitmap ret = filter.apply(bitmap, mScaleFactor, mQuality);
+        if (bitmap != ret) {
+            cache(bitmap);
+        }
         filter.setGeneralParameters();
         filter.setEnvironment(null);
         return ret;
index 88e8d42..3f71547 100644 (file)
@@ -24,6 +24,7 @@ import android.util.JsonWriter;
 import android.util.Log;
 
 import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.cache.BitmapCache;
 import com.android.gallery3d.filtershow.cache.ImageLoader;
 import com.android.gallery3d.filtershow.filters.BaseFiltersManager;
 import com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
@@ -235,6 +236,37 @@ public class ImagePreset {
         return true;
     }
 
+    public boolean equals(ImagePreset preset) {
+        if (preset == null) {
+            return false;
+        }
+
+        if (preset.mFilters.size() != mFilters.size()) {
+            return false;
+        }
+
+        if (mDoApplyGeometry != preset.mDoApplyGeometry) {
+            return false;
+        }
+
+        if (mDoApplyFilters != preset.mDoApplyFilters) {
+            if (mFilters.size() > 0 || preset.mFilters.size() > 0) {
+                return false;
+            }
+        }
+
+        for (int i = 0; i < preset.mFilters.size(); i++) {
+            FilterRepresentation a = preset.mFilters.elementAt(i);
+            FilterRepresentation b = mFilters.elementAt(i);
+
+            if (!a.equals(b)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     public int similarUpTo(ImagePreset preset) {
         for (int i = 0; i < preset.mFilters.size(); i++) {
             FilterRepresentation a = preset.mFilters.elementAt(i);
@@ -476,7 +508,11 @@ public class ImagePreset {
                     // TODO: might be worth getting rid of applyBorder.
                     continue;
                 }
+                Bitmap tmp = bitmap;
                 bitmap = environment.applyRepresentation(representation, bitmap);
+                if (tmp != bitmap) {
+                    environment.cache(tmp);
+                }
                 if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) {
                     UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
                             "SaveFilter", representation.getSerializationName(), 1);
index ef4bb9b..463b38d 100644 (file)
@@ -52,7 +52,8 @@ public class RenderingRequest {
 
     public static void post(Context context, Bitmap source, ImagePreset preset, int type,
                             RenderingRequestCaller caller, Rect bounds, Rect destination) {
-        if (((type != PARTIAL_RENDERING && type != HIGHRES_RENDERING) && source == null)
+        if (((type != PARTIAL_RENDERING && type != HIGHRES_RENDERING
+                && type != GEOMETRY_RENDERING && type != FILTERS_RENDERING) && source == null)
                 || preset == null || caller == null) {
             Log.v(LOGTAG, "something null: source: " + source
                     + " or preset: " + preset + " or caller: " + caller);
@@ -61,14 +62,15 @@ public class RenderingRequest {
         RenderingRequest request = new RenderingRequest();
         Bitmap bitmap = null;
         if (type == FULL_RENDERING
-                || type == GEOMETRY_RENDERING
                 || type == ICON_RENDERING
                 || type == STYLE_ICON_RENDERING) {
             CachingPipeline pipeline = new CachingPipeline(
                     FiltersManager.getManager(), "Icon");
             bitmap = pipeline.renderGeometryIcon(source, preset);
-        } else if (type != PARTIAL_RENDERING && type != HIGHRES_RENDERING) {
-            bitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), mConfig);
+        } else if (type != PARTIAL_RENDERING && type != HIGHRES_RENDERING
+                && type != GEOMETRY_RENDERING && type != FILTERS_RENDERING) {
+            bitmap = MasterImage.getImage().getBitmapCache().getBitmap(
+                    source.getWidth(), source.getHeight());
         }
 
         request.setBitmap(bitmap);
index 7a83f70..c8bc57d 100644 (file)
@@ -63,7 +63,13 @@ public class RenderingRequestTask extends ProcessingTask {
     public Result doInBackground(Request message) {
         RenderingRequest request = ((Render) message).request;
         RenderResult result = null;
-        mPreviewPipeline.render(request);
+        if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
+            mPreviewPipeline.renderGeometry(request);
+        } else if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
+            mPreviewPipeline.renderFilters(request);
+        } else {
+            mPreviewPipeline.render(request);
+        }
         result = new RenderResult();
         result.request = request;
         return result;