Merge "Add LUT3D filter state saving" into gb-ub-photos-carlsbad
diff --git a/res/layout-land/camera_controls.xml b/res/layout-land/camera_controls.xml
index 96f593a..432ae9e 100644
--- a/res/layout-land/camera_controls.xml
+++ b/res/layout-land/camera_controls.xml
@@ -21,6 +21,7 @@
 
         <View
             android:id="@+id/blocker"
+            android:clickable="true"
             android:layout_height="match_parent"
             android:layout_width="@dimen/switcher_size"
             android:layout_gravity="right" />
diff --git a/res/layout-port/camera_controls.xml b/res/layout-port/camera_controls.xml
index ebbdf26..7dd66e4 100644
--- a/res/layout-port/camera_controls.xml
+++ b/res/layout-port/camera_controls.xml
@@ -21,6 +21,7 @@
 
         <View
             android:id="@+id/blocker"
+            android:clickable="true"
             android:layout_width="match_parent"
             android:layout_height="@dimen/switcher_size"
             android:layout_gravity="bottom" />
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index f40c6ef..5457650 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -159,8 +159,10 @@
         <item>@string/pref_camera_picturesize_entry_5mp</item>
         <item>@string/pref_camera_picturesize_entry_5mp</item>
         <item>@string/pref_camera_picturesize_entry_5mp</item>
+        <item>@string/pref_camera_picturesize_entry_4mp</item>
         <item>@string/pref_camera_picturesize_entry_3mp</item>
         <item>@string/pref_camera_picturesize_entry_2mp</item>
+        <item>@string/pref_camera_picturesize_entry_2mp_wide</item>
         <item>@string/pref_camera_picturesize_entry_1_3mp</item>
         <item>@string/pref_camera_picturesize_entry_1mp</item>
         <item>@string/pref_camera_picturesize_entry_vga</item>
@@ -176,8 +178,10 @@
         <item>2592x1944</item>
         <item>2592x1936</item>
         <item>2560x1920</item>
+        <item>2688x1520</item>
         <item>2048x1536</item>
         <item>1600x1200</item>
+        <item>1920x1088</item>
         <item>1280x960</item>
         <item>1024x768</item>
         <item>640x480</item>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0ec4da6..cb4bc18 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -678,10 +678,14 @@
     <string name="pref_camera_picturesize_entry_8mp">8M pixels</string>
     <!-- Settings screen, dialog choice for 5 megapixels picture size [CHAR LIMIT=15] -->
     <string name="pref_camera_picturesize_entry_5mp">5M pixels</string>
+    <!-- Settings screen, dialog choice for 4 megapixels picture size [CHAR LIMIT=15] -->
+    <string name="pref_camera_picturesize_entry_4mp">4M pixels</string>
     <!-- Settings screen, dialog choice for 3 megapixels picture size [CHAR LIMIT=15] -->
     <string name="pref_camera_picturesize_entry_3mp">3M pixels</string>
     <!-- Settings screen, dialog choice for 2 megapixels picture size [CHAR LIMIT=15] -->
     <string name="pref_camera_picturesize_entry_2mp">2M pixels</string>
+    <!-- Settings screen, dialog choice for 2 megapixels picture size [CHAR LIMIT=15] -->
+    <string name="pref_camera_picturesize_entry_2mp_wide">2M pixels (16:9)</string>
     <!-- Settings screen, dialog choice for 1.3 megapixels picture size [CHAR LIMIT=15] -->
     <string name="pref_camera_picturesize_entry_1_3mp">1.3M pixels</string>
     <!-- Settings screen, dialog choice for 1 megapixels picture size [CHAR LIMIT=15] -->
diff --git a/src/com/android/camera/NewPreviewGestures.java b/src/com/android/camera/NewPreviewGestures.java
index 2718e55..39c4be6 100644
--- a/src/com/android/camera/NewPreviewGestures.java
+++ b/src/com/android/camera/NewPreviewGestures.java
@@ -19,11 +19,13 @@
 import android.os.Handler;
 import android.os.Message;
 import android.util.Log;
+import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 import android.view.View;
 import android.view.ViewConfiguration;
 
+import com.android.camera.PreviewGestures.SingleTapListener;
 import com.android.camera.PreviewGestures.SwipeListener;
 import com.android.camera.ui.PieRenderer;
 import com.android.camera.ui.RenderOverlay;
@@ -33,6 +35,10 @@
 import java.util.ArrayList;
 import java.util.List;
 
+/* NewPreviewGestures disambiguates touch events received on RenderOverlay
+ * and dispatch them to the proper recipient (i.e. zoom renderer or pie renderer).
+ * Touch events on CameraControls will be handled by framework.
+ * */
 public class NewPreviewGestures
         implements ScaleGestureDetector.OnScaleGestureListener {
 
@@ -54,29 +60,60 @@
 
     private NewCameraActivity mActivity;
     private SingleTapListener mTapListener;
-    private CancelEventListener mCancelEventListener;
     private RenderOverlay mOverlay;
     private PieRenderer mPie;
     private ZoomRenderer mZoom;
     private MotionEvent mDown;
     private MotionEvent mCurrent;
     private ScaleGestureDetector mScale;
-    private List<View> mReceivers;
     private int mMode;
     private int mSlop;
     private int mTapTimeout;
     private boolean mEnabled;
     private boolean mZoomOnly;
     private int mOrientation;
-    private int[] mLocation;
-    private SwipeListener mSwipeListener;
+    private GestureDetector mGestureDetector;
+
+    private GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
+        @Override
+        public void onLongPress (MotionEvent e) {
+            // Open pie
+            if (mPie != null && !mPie.showsItems()) {
+                openPie();
+            }
+        }
+
+        @Override
+        public boolean onSingleTapUp (MotionEvent e) {
+            // Tap to focus when pie is not open
+            if (mPie == null || !mPie.showsItems()) {
+                mTapListener.onSingleTapUp(null, (int) e.getX(), (int) e.getY());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+            if (mMode == MODE_ZOOM) return false;
+            int deltaX = (int) (e1.getX() - e2.getX());
+            int deltaY = (int) (e1.getY() - e2.getY());
+            if (deltaY > 2 * deltaX && deltaY > -2 * deltaX) {
+                // Open pie on swipe up
+                if (mPie != null && !mPie.showsItems()) {
+                    openPie();
+                    return true;
+                }
+            }
+            return false;
+        }
+    };
 
     private Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             if (msg.what == MSG_PIE) {
                 mMode = MODE_PIE;
                 openPie();
-                cancelActivityTouchHandling(mDown);
             }
         }
     };
@@ -85,16 +122,8 @@
         public void onSingleTapUp(View v, int x, int y);
     }
 
-    public interface CancelEventListener {
-        public void onTouchEventCancelled(MotionEvent cancelEvent);
-    }
-
-    interface SwipeListener {
-        public void onSwipe(int direction);
-    }
-
     public NewPreviewGestures(NewCameraActivity ctx, SingleTapListener tapListener,
-            ZoomRenderer zoom, PieRenderer pie, SwipeListener swipe) {
+            ZoomRenderer zoom, PieRenderer pie) {
         mActivity = ctx;
         mTapListener = tapListener;
         mPie = pie;
@@ -104,12 +133,7 @@
         mSlop = (int) ctx.getResources().getDimension(R.dimen.pie_touch_slop);
         mTapTimeout = ViewConfiguration.getTapTimeout();
         mEnabled = true;
-        mLocation = new int[2];
-        mSwipeListener = swipe;
-    }
-
-    public void setCancelEventListener(CancelEventListener listener) {
-        mCancelEventListener = listener;
+        mGestureDetector = new GestureDetector(mGestureListener);
     }
 
     public void setRenderOverlay(RenderOverlay overlay) {
@@ -122,26 +146,14 @@
 
     public void setEnabled(boolean enabled) {
         mEnabled = enabled;
-        if (!enabled) {
-            cancelPie();
-        }
     }
 
     public void setZoomOnly(boolean zoom) {
         mZoomOnly = zoom;
     }
 
-    public void addTouchReceiver(View v) {
-        if (mReceivers == null) {
-            mReceivers = new ArrayList<View>();
-        }
-        mReceivers.add(v);
-    }
-
-    public void clearTouchReceivers() {
-        if (mReceivers != null) {
-            mReceivers.clear();
-        }
+    public boolean isEnabled() {
+        return mEnabled;
     }
 
     public boolean dispatchTouch(MotionEvent m) {
@@ -150,121 +162,28 @@
         }
         mCurrent = m;
         if (MotionEvent.ACTION_DOWN == m.getActionMasked()) {
-            if (checkReceivers(m)) {
-                mMode = MODE_MODULE;
-                return false;
-            } else {
-                mMode = MODE_ALL;
-                mDown = MotionEvent.obtain(m);
-                if (mPie != null && mPie.showsItems()) {
-                    mMode = MODE_PIE;
-                    return sendToPie(m);
-                }
-                if (mPie != null && !mZoomOnly) {
-                    mHandler.sendEmptyMessageDelayed(MSG_PIE, TIMEOUT_PIE);
-                }
-                if (mZoom != null) {
-                    mScale.onTouchEvent(m);
-                }
-                // make sure this is ok
-                return false;
-            }
-        } else if (mMode == MODE_NONE) {
-            return false;
-        } else if (mMode == MODE_SWIPE) {
-            if (MotionEvent.ACTION_UP == m.getActionMasked()) {
-                mSwipeListener.onSwipe(getSwipeDirection(m));
-            }
-            return true;
-        } else if (mMode == MODE_PIE) {
-            if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
-                sendToPie(makeCancelEvent(m));
-                if (mZoom != null) {
-                    onScaleBegin(mScale);
-                }
-            } else {
-                return sendToPie(m);
-            }
-            return true;
-        } else if (mMode == MODE_ZOOM) {
-            mScale.onTouchEvent(m);
-            if (!mScale.isInProgress() && MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
-                mMode = MODE_NONE;
-                onScaleEnd(mScale);
-            }
-            return true;
-        } else if (mMode == MODE_MODULE) {
-            return false;
-        } else {
-            // didn't receive down event previously;
-            // assume module wasn't initialzed and ignore this event.
-            if (mDown == null) {
-                return true;
-            }
-            if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
-                if (!mZoomOnly) {
-                    cancelPie();
-                    sendToPie(makeCancelEvent(m));
-                }
-                if (mZoom != null) {
-                    mScale.onTouchEvent(m);
-                    onScaleBegin(mScale);
-                }
-            } else if ((mMode == MODE_ZOOM) && !mScale.isInProgress()
-                    && MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
-                // user initiated and stopped zoom gesture without zooming
-                mScale.onTouchEvent(m);
-                onScaleEnd(mScale);
-            }
-            // not zoom or pie mode and no timeout yet
-            if (mZoom != null) {
-                boolean res = mScale.onTouchEvent(m);
-                if (mScale.isInProgress()) {
-                    cancelPie();
-                    cancelActivityTouchHandling(m);
-                    return res;
-                }
-            }
-            if (MotionEvent.ACTION_UP == m.getActionMasked()) {
-                cancelPie();
-                cancelActivityTouchHandling(m);
-                // must have been tap
-                if (m.getEventTime() - mDown.getEventTime() < mTapTimeout) {
-                    mTapListener.onSingleTapUp(null,
-                            (int) mDown.getX() - mOverlay.getWindowPositionX(),
-                            (int) mDown.getY() - mOverlay.getWindowPositionY());
-                    return true;
-                } else {
-                    return false;
-                }
-            } else if (MotionEvent.ACTION_MOVE == m.getActionMasked()) {
-                if ((Math.abs(m.getX() - mDown.getX()) > mSlop)
-                        || Math.abs(m.getY() - mDown.getY()) > mSlop) {
-                    // moved too far and no timeout yet, no focus or pie
-                    cancelPie();
-                    int dir = getSwipeDirection(m);
-                    if (dir == DIR_LEFT) {
-                        mMode = MODE_MODULE;
-                        return false;
-                    } else {
-                        cancelActivityTouchHandling(m);
-                        mMode = MODE_NONE;
-                    }
-                }
-            }
-            return false;
+            mMode = MODE_NONE;
+            mDown = MotionEvent.obtain(m);
         }
-    }
 
-    private boolean checkReceivers(MotionEvent m) {
-        if (mReceivers != null) {
-            for (View receiver : mReceivers) {
-                if (isInside(m, receiver)) {
-                    return true;
-                }
+        // If pie is open, redirects all the touch events to pie.
+        if (mPie != null && mPie.isOpen()) {
+            return sendToPie(m);
+        }
+
+        // If pie is not open, send touch events to gesture detector and scale
+        // listener to recognize the gesture.
+        mGestureDetector.onTouchEvent(m);
+        if (mZoom != null) {
+            mScale.onTouchEvent(m);
+            if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
+                mMode = MODE_ZOOM;
+                mZoom.onScaleBegin(mScale);
+            } else if (MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
+                mZoom.onScaleEnd(mScale);
             }
         }
-        return false;
+        return true;
     }
 
     // left tests for finger moving right to left
@@ -295,19 +214,6 @@
         return DIR_UP;
     }
 
-    private boolean isInside(MotionEvent evt, View v) {
-        v.getLocationInWindow(mLocation);
-        return (v.getVisibility() == View.VISIBLE
-                && evt.getX() >= mLocation[0] && evt.getX() < mLocation[0] + v.getWidth()
-                && evt.getY() >= mLocation[1] && evt.getY() < mLocation[1] + v.getHeight());
-    }
-
-    public void cancelActivityTouchHandling(MotionEvent m) {
-        if (mCancelEventListener != null) {
-            mCancelEventListener.onTouchEventCancelled(makeCancelEvent(m));
-        }
-    }
-
     private MotionEvent makeCancelEvent(MotionEvent m) {
         MotionEvent c = MotionEvent.obtain(m);
         c.setAction(MotionEvent.ACTION_CANCEL);
@@ -315,21 +221,16 @@
     }
 
     private void openPie() {
-        mDown.offsetLocation(-mOverlay.getWindowPositionX(),
-                -mOverlay.getWindowPositionY());
+        mGestureDetector.onTouchEvent(makeCancelEvent(mDown));
+        mScale.onTouchEvent(makeCancelEvent(mDown));
         mOverlay.directDispatchTouch(mDown, mPie);
     }
 
-    private void cancelPie() {
-        mHandler.removeMessages(MSG_PIE);
-    }
-
     private boolean sendToPie(MotionEvent m) {
-        m.offsetLocation(-mOverlay.getWindowPositionX(),
-                -mOverlay.getWindowPositionY());
         return mOverlay.directDispatchTouch(m, mPie);
     }
 
+    // OnScaleGestureListener implementation
     @Override
     public boolean onScale(ScaleGestureDetector detector) {
         return mZoom.onScale(detector);
@@ -337,22 +238,17 @@
 
     @Override
     public boolean onScaleBegin(ScaleGestureDetector detector) {
-        if (mMode != MODE_ZOOM) {
+        if (mPie == null || !mPie.isOpen()) {
             mMode = MODE_ZOOM;
-            cancelActivityTouchHandling(mCurrent);
-        }
-        if (mCurrent.getActionMasked() != MotionEvent.ACTION_MOVE) {
+            mGestureDetector.onTouchEvent(makeCancelEvent(mCurrent));
             return mZoom.onScaleBegin(detector);
-        } else {
-            return true;
         }
+        return false;
     }
 
     @Override
     public void onScaleEnd(ScaleGestureDetector detector) {
-        if (mCurrent.getActionMasked() != MotionEvent.ACTION_MOVE) {
-            mZoom.onScaleEnd(detector);
-        }
+        mZoom.onScaleEnd(detector);
     }
 }
 
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
index 91bf676..3bb60bb 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
@@ -268,4 +268,9 @@
             }
         }
     }
+
+    // Override this in subclasses
+    public int getStyle() {
+        return -1;
+    }
 }