Merge "Fix 4442284 Android Picasa sync over HTTP - data and credentials sent in clear text. DO NOT MERGE." into gingerbread
diff --git a/src/com/cooliris/cache/CacheService.java b/src/com/cooliris/cache/CacheService.java
index c8a5fc0..6f68913 100644
--- a/src/com/cooliris/cache/CacheService.java
+++ b/src/com/cooliris/cache/CacheService.java
@@ -1011,26 +1011,33 @@
                         }
                         ++ctr;
                     } while (ctr < numSets);
-                    // We now check for any deleted sets.
-                    final byte[] albumData = sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0);
-                    if (albumData != null && albumData.length > 0) {
-                        final DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256));
-                        try {
-                            final int numAlbums = dis.readInt();
-                            for (int i = 0; i < numAlbums; ++i) {
-                                final long setId = dis.readLong();
-                                Utils.readUTF(dis);
-                                dis.readBoolean();
-                                dis.readBoolean();
-                                if (!setIds.contains(setId)) {
+                }
+                // We now check for any deleted sets.
+                final byte[] albumData = sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0);
+                if (albumData != null && albumData.length > 0) {
+                    final DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256));
+                    try {
+                        final int numAlbums = dis.readInt();
+                        for (int i = 0; i < numAlbums; ++i) {
+                            final long setId = dis.readLong();
+                            Utils.readUTF(dis);
+                            dis.readBoolean();
+                            dis.readBoolean();
+                            if (!setIds.contains(setId)) {
+                                final byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_INDEX, 0);
+                                if (existingData != null && existingData.length == 1
+                                    && existingData[0] == sDummyData[0]) {
+                                    // markDirty() was already called, skip this time.
+                                    // (not do it too aggressively)
+                                } else {
                                     // This set was deleted, we need to recompute the cache.
                                     markDirty();
-                                    break;
                                 }
+                                break;
                             }
-                        } catch (Exception e) {
-                            ;
                         }
+                    } catch (Exception e) {
+                        ;
                     }
                 }
             } finally {
diff --git a/src/com/cooliris/media/GridCameraManager.java b/src/com/cooliris/media/GridCameraManager.java
index 7b6e05f..5b75b65 100644
--- a/src/com/cooliris/media/GridCameraManager.java
+++ b/src/com/cooliris/media/GridCameraManager.java
@@ -107,25 +107,37 @@
                     imgBottomRight.set(position.x + width, position.y + height, 0);
                     camera.convertToCameraSpace(0, 0, 0, topLeft);
                     camera.convertToCameraSpace(camera.mWidth, camera.mHeight, 0, bottomRight);
-                    float leftExtent = topLeft.x - imgTopLeft.x;
-                    float rightExtent = bottomRight.x - imgBottomRight.x;
                     camera.mConvergenceSpeed = 2.0f;
                     camera.mFriction = 0.0f;
-                    if (leftExtent < 0) {
-                        retVal = true;
-                        camera.moveBy(-leftExtent, 0, 0);
+                    if ((bottomRight.x - topLeft.x) > (imgBottomRight.x - imgTopLeft.x)) {
+                        final float hCenterExtent= (bottomRight.x + topLeft.x)/2 -
+                            (imgBottomRight.x + imgTopLeft.x)/2;
+                        camera.moveBy(-hCenterExtent, 0, 0);
+                    } else {
+                        float leftExtent = topLeft.x - imgTopLeft.x;
+                        float rightExtent = bottomRight.x - imgBottomRight.x;
+                        if (leftExtent < 0) {
+                            retVal = true;
+                            camera.moveBy(-leftExtent, 0, 0);
+                        }
+                        if (rightExtent > 0) {
+                            retVal = true;
+                            camera.moveBy(-rightExtent, 0, 0);
+                        }
                     }
-                    if (rightExtent > 0) {
-                        retVal = true;
-                        camera.moveBy(-rightExtent, 0, 0);
-                    }
-                    float topExtent = topLeft.y - imgTopLeft.y;
-                    float bottomExtent = bottomRight.y - imgBottomRight.y;
-                    if (topExtent < 0) {
-                        camera.moveBy(0, -topExtent, 0);
-                    }
-                    if (bottomExtent > 0) {
-                        camera.moveBy(0, -bottomExtent, 0);
+                    if ((bottomRight.y - topLeft.y) > (imgBottomRight.y - imgTopLeft.y)) {
+                        final float vCenterExtent= (bottomRight.y + topLeft.y)/2 -
+                            (imgBottomRight.y + imgTopLeft.y)/2;
+                        camera.moveBy(0, -vCenterExtent, 0);
+                    } else {
+                        float topExtent = topLeft.y - imgTopLeft.y;
+                        float bottomExtent = bottomRight.y - imgBottomRight.y;
+                        if (topExtent < 0) {
+                            camera.moveBy(0, -topExtent, 0);
+                        }
+                        if (bottomExtent > 0) {
+                            camera.moveBy(0, -bottomExtent, 0);
+                        }
                     }
                 }
             } finally {
diff --git a/src/com/cooliris/media/GridInputProcessor.java b/src/com/cooliris/media/GridInputProcessor.java
index 91dfd47..a4055db 100644
--- a/src/com/cooliris/media/GridInputProcessor.java
+++ b/src/com/cooliris/media/GridInputProcessor.java
@@ -26,11 +26,14 @@
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.WindowManager;
+import android.content.pm.PackageManager;
 
 import com.cooliris.app.App;
+import com.cooliris.media.Vector3f;
 
 public final class GridInputProcessor implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener,
         ScaleGestureDetector.OnScaleGestureListener {
+    private MotionEvent mPrevEvent;
     private int mCurrentFocusSlot;
     private boolean mCurrentFocusIsPressed;
     private int mCurrentSelectedSlot;
@@ -64,6 +67,12 @@
     private boolean mZoomGesture;
     private int mCurrentScaleSlot;
     private float mScale;
+    // Added for supporting moving pinch zoom center
+    private float mPrevFocusX;
+    private float mPrevFocusY;
+    private float mFocusX;
+    private float mFocusY;
+    private boolean mSupportPanAndZoom;
 
     public GridInputProcessor(Context context, GridCamera camera, GridLayer layer, RenderView view, Pool<Vector3f> pool,
             DisplayItem[] displayItems) {
@@ -80,6 +89,8 @@
         mGestureDetector.setIsLongpressEnabled(true);
         mZoomGesture = false;
         mScale = 1.0f;
+        mSupportPanAndZoom = context.getPackageManager().hasSystemFeature(
+            PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT);
         {
             WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
             mDisplay = windowManager.getDefaultDisplay();
@@ -166,6 +177,18 @@
         mPrevTouchTime = timestamp;
         float timeElapsed = (float) delta;
         timeElapsed = timeElapsed * 0.001f; // division by 1000 for seconds
+
+        if (!mScaleGestureDetector.isInProgress()
+                    && (mActionCode == MotionEvent.ACTION_POINTER_1_DOWN ||
+                            mActionCode == MotionEvent.ACTION_POINTER_2_DOWN)
+                    && event.getPointerCount() >= 2) {
+                if (mPrevEvent != null) {
+                    mPrevEvent.recycle();
+                }
+                mPrevEvent = MotionEvent.obtain(event);
+                setPrevFocus(event);
+        }
+
         switch (mActionCode) {
         case MotionEvent.ACTION_UP:
             touchEnded(mTouchPosX, mTouchPosY, timeElapsed);
@@ -176,6 +199,7 @@
             break;
         case MotionEvent.ACTION_MOVE:
             touchMoved(mTouchPosX, mTouchPosY, timeElapsed);
+            setPrevFocus(event);
             break;
         }
         if (!mZoomGesture)
@@ -299,6 +323,43 @@
         }
         return false;
     }
+    private void setPrevFocus(MotionEvent event){
+
+        if(mPrevEvent == null) {
+            mPrevEvent  = MotionEvent.obtain(event);
+        }
+        final MotionEvent prev = mPrevEvent;
+
+        final float px0 = prev.getX(0);
+        final float py0 = prev.getY(0);
+        final float px1 = prev.getX(1);
+        final float py1 = prev.getY(1);
+        final float cx0 = event.getX(0);
+        final float cy0 = event.getY(0);
+        final float cx1 = event.getX(1);
+        final float cy1 = event.getY(1);
+
+        final float pvx = px1 - px0;
+        final float pvy = py1 - py0;
+        final float cvx = cx1 - cx0;
+        final float cvy = cy1 - cy0;
+
+        // Added for supporting moving pinch zoom center
+        mPrevFocusX = mFocusX;
+        mPrevFocusY = mFocusY;
+
+        mFocusX = cx0 + cvx * 0.5f;
+        mFocusY = cy0 + cvy * 0.5f;
+
+    }
+    // Added for supporting moving pinch zoom center
+    public float getPrevFocusX() {
+        return mPrevFocusX;
+    }
+
+    public float getPrevFocusY() {
+        return mPrevFocusY;
+    }
 
     private void touchBegan(int posX, int posY) {
         mPrevTouchPosX = posX;
@@ -756,18 +817,33 @@
         if (Float.isInfinite(scale) || Float.isNaN(scale))
             return true;
         mScale = scale * mScale;
-        boolean performTranslation = Math.abs(scale - 1.0f) < 0.001f ? false : true;
-        if (layer.getState() == GridLayer.STATE_FULL_SCREEN) {
+        boolean performTranslation = true;
+        if (mSupportPanAndZoom && layer.getState() == GridLayer.STATE_FULL_SCREEN) {
             float currentScale = layer.getZoomValue();
             if (currentScale <= 1.0f)
                 performTranslation = false;
             final Vector3f retVal = new Vector3f();
+            final Vector3f retValCenter = new Vector3f();
+            final Vector3f retValPrev = new Vector3f();
             if (performTranslation) {
                 float posX = detector.getFocusX();
                 float posY = detector.getFocusY();
                 posX -= (mCamera.mWidth / 2);
                 posY -= (mCamera.mHeight / 2);
                 mCamera.convertToRelativeCameraSpace(posX, posY, 0, retVal);
+                mCamera.convertToRelativeCameraSpace(0, 0, 0, retValCenter);
+
+                float posPrevX = getPrevFocusX();
+                float posPrevY = getPrevFocusY();
+
+                posPrevX -= (mCamera.mWidth / 2);
+                posPrevY -= (mCamera.mHeight / 2);
+                mCamera.convertToRelativeCameraSpace(posPrevX, posPrevY, 0, retValPrev);
+                posX = detector.getFocusX();
+                posY = detector.getFocusY();
+                posX -= (mCamera.mWidth / 2);
+                posY -= (mCamera.mHeight / 2);
+                mCamera.convertToRelativeCameraSpace(posX, posY, 0, retVal);
             }
             if (currentScale < 0.7f && scale < 1.0f) {
                 scale = 1.0f;
@@ -778,8 +854,10 @@
             layer.setZoomValue(currentScale * scale);
             if (performTranslation) {
                 mCamera.update(0.001f);
+                // Calculate amount of translation for moving zoom center
+                retVal.x= (retVal.x - retValCenter.x)*(1.0f-1.0f/scale) + (retValPrev.x-retVal.x);
+                retVal.y= (retVal.y - retValCenter.y)*(1.0f-1.0f/scale) + (retValPrev.y-retVal.y);
                 mCamera.moveBy(retVal.x, retVal.y, 0);
-                layer.constrainCameraForSlot(mCurrentSelectedSlot);
             }
         }
         if (mLayer.getState() == GridLayer.STATE_GRID_VIEW) {
diff --git a/src/com/cooliris/media/GridLayer.java b/src/com/cooliris/media/GridLayer.java
index 74aff5d..d15c266 100644
--- a/src/com/cooliris/media/GridLayer.java
+++ b/src/com/cooliris/media/GridLayer.java
@@ -1431,7 +1431,7 @@
 
     public void setZoomValue(float f) {
         mZoomValue = f;
-        centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
+        centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 10.0f);
     }
 
     public void setPickIntent(boolean b) {
diff --git a/src/com/cooliris/media/MediaBucketList.java b/src/com/cooliris/media/MediaBucketList.java
index a1a30e9..131e19c 100644
--- a/src/com/cooliris/media/MediaBucketList.java
+++ b/src/com/cooliris/media/MediaBucketList.java
@@ -130,7 +130,8 @@
         // Search for the bucket for this media set
         for (int i = 0; i < numSelectedBuckets; ++i) {
             final MediaBucket bucketCompare = selectedBuckets.get(i);
-            if (bucketCompare.mediaSet != null && mediaSetToAdd != null && bucketCompare.mediaSet.mId == mediaSetToAdd.mId) {
+            if (bucketCompare != null && bucketCompare.mediaSet != null
+                && mediaSetToAdd != null && bucketCompare.mediaSet == mediaSetToAdd) {
                 // We found the MediaSet.
                 if (!hasExpandedMediaSet) {
                     // Remove this bucket from the list since this bucket was
@@ -171,7 +172,7 @@
                         boolean foundIndex = false;
                         for (int j = 0; j < numPresentItems; ++j) {
                             final MediaItem selectedItem = selectedItems.get(j);
-                            if (selectedItem != null && item != null && selectedItem.mId == item.mId) {
+                            if (selectedItem != null && item != null && selectedItem == item) {
                                 // This index was already present, we need to
                                 // remove it.
                                 foundIndex = true;
diff --git a/src/com/cooliris/media/MediaFeed.java b/src/com/cooliris/media/MediaFeed.java
index c190ef9..d99c08f 100644
--- a/src/com/cooliris/media/MediaFeed.java
+++ b/src/com/cooliris/media/MediaFeed.java
@@ -191,6 +191,18 @@
     }
 
     public MediaSet addMediaSet(final long setId, DataSource dataSource) {
+        int numSets = mMediaSets.size();
+        for (int i = 0; i < numSets; i++) {
+            MediaSet set = mMediaSets.get(i);
+            if ((set.mId == setId) && (set.mDataSource == dataSource)) {
+                // The mediaset already exists, but might be out-dated.
+                // To avoid the same mediaset being added twice, we delete
+                // the old one first, then add the new one below.
+                mMediaSets.remove(i);
+                break;
+            }
+        }
+
         MediaSet mediaSet = new MediaSet(dataSource);
         mediaSet.mId = setId;
         mMediaSets.add(mediaSet);
diff --git a/src/com/cooliris/media/ScaleGestureDetector.java b/src/com/cooliris/media/ScaleGestureDetector.java
index 7ebb274..326fbbd 100644
--- a/src/com/cooliris/media/ScaleGestureDetector.java
+++ b/src/com/cooliris/media/ScaleGestureDetector.java
@@ -305,7 +305,7 @@
         mTimeDelta = curr.getEventTime() - prev.getEventTime();
         mCurrPressure = curr.getPressure(0) + curr.getPressure(1);
         mPrevPressure = prev.getPressure(0) + prev.getPressure(1);
-        
+
         // Update the correct finger.
         mBottomFingerCurrX = cx0;
         mBottomFingerCurrY = cy0;