OSDN Git Service

Updates to 3D gallery source.
[android-x86/packages-apps-Gallery2.git] / src / com / cooliris / media / GridInputProcessor.java
1 package com.cooliris.media;
2
3 import android.content.Context;
4 import android.hardware.Sensor;
5 import android.hardware.SensorEvent;
6 import android.os.SystemClock;
7 import android.view.GestureDetector;
8 import android.view.HapticFeedbackConstants;
9 import android.view.KeyEvent;
10 import android.view.MotionEvent;
11
12 public final class GridInputProcessor implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
13     private int mCurrentFocusSlot;
14     private boolean mCurrentFocusIsPressed;
15     private int mCurrentSelectedSlot;
16
17     private float mPrevTiltValueLowPass;
18     private float mPrevShakeValueHighPass;
19     private float mShakeValue;
20     private int mTouchPosX;
21     private int mTouchPosY;
22     private int mActionCode;
23     private long mPrevTouchTime;
24     private float mFirstTouchPosX;
25     private float mFirstTouchPosY;
26     private float mPrevTouchPosX;
27     private float mPrevTouchPosY;
28     private float mTouchVelX;
29     private float mTouchVelY;
30     private boolean mProcessTouch;
31     private boolean mTouchMoved;
32     private float mDpadIgnoreTime = 0.0f;
33     private GridCamera mCamera;
34     private GridLayer mLayer;
35     private Context mContext;
36     private Pool<Vector3f> mPool;
37     private DisplayItem[] mDisplayItems;
38     private boolean mPrevHitEdge;
39     private boolean mTouchFeedbackDelivered;
40     private GestureDetector mGestureDetector;
41     private RenderView mView;
42
43     public GridInputProcessor(Context context, GridCamera camera, GridLayer layer, RenderView view, Pool<Vector3f> pool,
44             DisplayItem[] displayItems) {
45         mPool = pool;
46         mCamera = camera;
47         mLayer = layer;
48         mCurrentFocusSlot = Shared.INVALID;
49         mCurrentSelectedSlot = Shared.INVALID;
50         mContext = context;
51         mDisplayItems = displayItems;
52         mGestureDetector = new GestureDetector(context, this);
53         mGestureDetector.setIsLongpressEnabled(true);
54         mView = view;
55     }
56
57     public int getCurrentFocusSlot() {
58         return mCurrentFocusSlot;
59     }
60
61     public int getCurrentSelectedSlot() {
62         return mCurrentSelectedSlot;
63     }
64
65     public void setCurrentSelectedSlot(int slot) {
66         mCurrentSelectedSlot = slot;
67         GridLayer layer = mLayer;
68         layer.setState(GridLayer.STATE_FULL_SCREEN);
69         mCamera.mConvergenceSpeed = 2.0f;
70         DisplayItem displayItem = layer.getDisplayItemForSlotId(slot);
71         MediaItem item = null;
72         if (displayItem != null)
73             item = displayItem.mItemRef;
74         layer.getHud().fullscreenSelectionChanged(item, mCurrentSelectedSlot + 1, layer.getCompleteRange().end + 1);
75     }
76
77     public void onSensorChanged(RenderView view, SensorEvent event, int state) {
78         switch (event.sensor.getType()) {
79         case Sensor.TYPE_ACCELEROMETER:
80         case Sensor.TYPE_ORIENTATION:
81             float[] values = event.values;
82             float valueToUse = (mCamera.mWidth < mCamera.mHeight) ? values[0] : -values[1];
83             float tiltValue = 0.8f * mPrevTiltValueLowPass + 0.2f * valueToUse;
84             if (Math.abs(tiltValue) < 0.5f)
85                 tiltValue = 0.0f;
86             if (state == GridLayer.STATE_FULL_SCREEN)
87                 tiltValue = 0.0f;
88             if (tiltValue != 0.0f)
89                 view.requestRender();
90             mCamera.mEyeOffsetX = -3.0f * tiltValue;
91             float shakeValue = values[1] * values[1] + values[2] * values[2];
92             mShakeValue = shakeValue - mPrevShakeValueHighPass;
93             mPrevShakeValueHighPass = shakeValue;
94             if (mShakeValue < 16.0f) {
95                 mShakeValue = 0;
96             } else {
97                 mShakeValue = mShakeValue * 4.0f;
98                 if (mShakeValue > 200) {
99                     mShakeValue = 200;
100                 }
101             }
102             break;
103         }
104     }
105
106     public boolean onTouchEvent(MotionEvent event) {
107         mTouchPosX = (int) (event.getX());
108         mTouchPosY = (int) (event.getY());
109         mActionCode = event.getAction();
110         long timestamp = SystemClock.elapsedRealtime();
111         long delta = timestamp - mPrevTouchTime;
112         mPrevTouchTime = timestamp;
113         float timeElapsed = (float) delta;
114         timeElapsed = timeElapsed * 0.001f; // division by 1000 for seconds
115         switch (mActionCode) {
116         case MotionEvent.ACTION_UP:
117             if (mProcessTouch == false) {
118                 touchBegan(mTouchPosX, mTouchPosY);
119             }
120             touchEnded(mTouchPosX, mTouchPosY, timeElapsed);
121             break;
122         case MotionEvent.ACTION_DOWN:
123             mPrevTouchTime = timestamp;
124             touchBegan(mTouchPosX, mTouchPosY);
125             break;
126         case MotionEvent.ACTION_MOVE:
127             touchMoved(mTouchPosX, mTouchPosY, timeElapsed);
128             break;
129         }
130         mGestureDetector.onTouchEvent(event);
131         return true;
132     }
133
134     public boolean onKeyDown(int keyCode, KeyEvent event, int state) {
135         GridLayer layer = mLayer;
136         if (keyCode == KeyEvent.KEYCODE_BACK) {
137             if (layer.getViewIntent())
138                 return false;
139             if (layer.getHud().getMode() == HudLayer.MODE_SELECT) {
140                 layer.deselectAll();
141                 return true;
142             }
143             if (layer.inSlideShowMode()) {
144                 layer.endSlideshow();
145                 layer.getHud().setAlpha(1.0f);
146                 return true;
147             }
148             float zoomValue = layer.getZoomValue();
149             if (zoomValue != 1.0f) {
150                 layer.setZoomValue(1.0f);
151                 layer.centerCameraForSlot(mCurrentSelectedSlot, 1.0f);
152                 return true;
153             }
154             layer.goBack();
155             if (state == GridLayer.STATE_MEDIA_SETS)
156                 return false;
157             return true;
158         }
159         if (mDpadIgnoreTime < 0.1f)
160             return true;
161         mDpadIgnoreTime = 0.0f;
162         IndexRange bufferedVisibleRange = layer.getBufferedVisibleRange();
163         int firstBufferedVisibleSlot = bufferedVisibleRange.begin;
164         int lastBufferedVisibleSlot = bufferedVisibleRange.end;
165         int anchorSlot = layer.getAnchorSlotIndex(GridLayer.ANCHOR_CENTER);
166         if (state == GridLayer.STATE_FULL_SCREEN) {
167             layer.endSlideshow();
168             boolean needsVibrate = false;
169             if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
170                 needsVibrate = !layer.changeFocusToNextSlot(1.0f);
171             }
172             if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
173                 needsVibrate = !layer.changeFocusToPreviousSlot(1.0f);
174             }
175             if (needsVibrate) {
176                 vibrateShort();
177             }
178             if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER && !mCamera.isAnimating()) {
179                 if (layer.getZoomValue() == 1.0f)
180                     layer.zoomInToSelectedItem();
181                 else
182                     layer.setZoomValue(1.0f);
183             }
184             if (keyCode == KeyEvent.KEYCODE_MENU) {
185                 if (layer.getHud().getMode() == HudLayer.MODE_NORMAL)
186                     layer.enterSelectionMode();
187                 else
188                     layer.deselectAll();
189             }
190         } else {
191             mCurrentFocusIsPressed = false;
192             int numRows = ((GridLayoutInterface) layer.getLayoutInterface()).mNumRows;
193             if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER && mCurrentFocusSlot != Shared.INVALID) {
194                 if (layer.getHud().getMode() != HudLayer.MODE_SELECT) {
195                     boolean centerCamera = layer.tapGesture(mCurrentFocusSlot, false);
196                     if (centerCamera) {
197                         int slotId = mCurrentFocusSlot;
198                         selectSlot(slotId);
199                     }
200                     mCurrentFocusSlot = Shared.INVALID;
201                     return true;
202                 } else {
203                     layer.addSlotToSelectedItems(mCurrentFocusSlot, true, true);
204                 }
205                 mCurrentFocusIsPressed = true;
206             } else if (keyCode == KeyEvent.KEYCODE_MENU && mCurrentFocusSlot != Shared.INVALID) {
207                 if (layer.getHud().getMode() == HudLayer.MODE_NORMAL)
208                     layer.enterSelectionMode();
209                 else
210                     layer.deselectAll();
211             } else if (mCurrentFocusSlot == Shared.INVALID) {
212                 mCurrentFocusSlot = anchorSlot;
213             } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
214                 mCurrentFocusSlot += numRows;
215             } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
216                 mCurrentFocusSlot -= numRows;
217             } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
218                 --mCurrentFocusSlot;
219             } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
220                 ++mCurrentFocusSlot;
221             }
222             if (mCurrentFocusSlot > lastBufferedVisibleSlot) {
223                 mCurrentFocusSlot = lastBufferedVisibleSlot;
224             }
225             if (mCurrentFocusSlot < firstBufferedVisibleSlot)
226                 mCurrentFocusSlot = firstBufferedVisibleSlot;
227             if (mCurrentFocusSlot != Shared.INVALID) {
228                 layer.centerCameraForSlot(mCurrentFocusSlot, 1.0f);
229             }
230         }
231         return false;
232     }
233
234     private void touchBegan(int posX, int posY) {
235         mPrevTouchPosX = posX;
236         mPrevTouchPosY = posY;
237         mFirstTouchPosX = posX;
238         mFirstTouchPosY = posY;
239         mTouchVelX = 0;
240         mTouchVelY = 0;
241         mProcessTouch = true;
242         mTouchMoved = false;
243         mCamera.stopMovementInX();
244         GridLayer layer = mLayer;
245         mCurrentFocusSlot = layer.getSlotIndexForScreenPosition(posX, posY);
246         mCurrentFocusIsPressed = true;
247         mTouchFeedbackDelivered = false;
248         HudLayer hud = layer.getHud();
249         if (hud.getMode() == HudLayer.MODE_SELECT)
250             hud.closeSelectionMenu();
251         if (layer.getState() == GridLayer.STATE_FULL_SCREEN && hud.getMode() == HudLayer.MODE_SELECT) {
252             layer.deselectAll();
253             hud.setAlpha(1.0f);
254         }
255         int slotId = layer.getSlotIndexForScreenPosition(posX, posY);
256         if (slotId != Shared.INVALID && layer.getState() != GridLayer.STATE_FULL_SCREEN) {
257             vibrateShort();
258         }
259     }
260
261     private void touchMoved(int posX, int posY, float timeElapsedx) {
262         if (mProcessTouch) {
263             GridLayer layer = mLayer;
264             GridCamera camera = mCamera;
265             float deltaX = -(posX - mPrevTouchPosX); // negation since the wall
266             // moves in a direction
267             // opposite to that of
268             // the touch
269             float deltaY = -(posY - mPrevTouchPosY);
270             if (Math.abs(deltaX) >= 10.0f || Math.abs(deltaY) >= 10.0f) {
271                 mTouchMoved = true;
272             }
273             Pool<Vector3f> pool = mPool;
274             Vector3f firstPosition = pool.create();
275             Vector3f lastPosition = pool.create();
276             Vector3f deltaAnchorPosition = pool.create();
277             Vector3f worldPosDelta = pool.create();
278             try {
279                 deltaAnchorPosition.set(layer.getDeltaAnchorPosition());
280                 LayoutInterface layout = layer.getLayoutInterface();
281                 GridCameraManager.getSlotPositionForSlotIndex(0, camera, layout, deltaAnchorPosition, firstPosition);
282                 int lastSlotIndex = 0;
283                 IndexRange completeRange = layer.getCompleteRange();
284                 synchronized (completeRange) {
285                     lastSlotIndex = completeRange.end;
286                 }
287                 GridCameraManager.getSlotPositionForSlotIndex(lastSlotIndex, camera, layout, deltaAnchorPosition, lastPosition);
288
289                 camera.convertToRelativeCameraSpace(deltaX, deltaY, 0, worldPosDelta);
290                 deltaX = worldPosDelta.x;
291                 deltaY = worldPosDelta.y;
292                 camera.moveBy(deltaX, (layer.getZoomValue() == 1.0f) ? 0 : deltaY, 0);
293                 deltaX *= camera.mScale;
294                 deltaY *= camera.mScale;
295             } finally {
296                 pool.delete(firstPosition);
297                 pool.delete(lastPosition);
298                 pool.delete(deltaAnchorPosition);
299                 pool.delete(worldPosDelta);
300             }
301             if (layer.getZoomValue() == 1.0f) {
302                 if (camera
303                         .computeConstraints(false, (layer.getState() != GridLayer.STATE_FULL_SCREEN), firstPosition, lastPosition)) {
304                     deltaX = 0.0f;
305                     // vibrate
306                     if (!mTouchFeedbackDelivered) {
307                         mTouchFeedbackDelivered = true;
308                         vibrateLong();
309                     }
310                 }
311             }
312             mTouchVelX = deltaX * timeElapsedx;
313             mTouchVelY = deltaY * timeElapsedx;
314             float maxVelXx = (mCamera.mWidth * 0.5f);
315             float maxVelYx = (mCamera.mHeight);
316             mTouchVelX = FloatUtils.clamp(mTouchVelX, -maxVelXx, maxVelXx);
317             mTouchVelY = FloatUtils.clamp(mTouchVelY, -maxVelYx, maxVelYx);
318             mPrevTouchPosX = posX;
319             mPrevTouchPosY = posY;
320             // you want the movement to track the finger immediately
321             if (mTouchMoved == false)
322                 mCurrentFocusSlot = layer.getSlotIndexForScreenPosition(posX, posY);
323             else
324                 mCurrentFocusSlot = Shared.INVALID;
325             if (!mCamera.isZAnimating()) {
326                 mCamera.commitMoveInX();
327                 mCamera.commitMoveInY();
328             }
329             int anchorSlotIndex = layer.getAnchorSlotIndex(GridLayer.ANCHOR_LEFT);
330             DisplayItem[] displayItems = mDisplayItems;
331             IndexRange bufferedVisibleRange = layer.getBufferedVisibleRange();
332             int firstBufferedVisibleSlot = bufferedVisibleRange.begin;
333             int lastBufferedVisibleSlot = bufferedVisibleRange.end;
334             synchronized (displayItems) {
335                 if (anchorSlotIndex >= firstBufferedVisibleSlot && anchorSlotIndex <= lastBufferedVisibleSlot) {
336                     DisplayItem item = displayItems[(anchorSlotIndex - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT];
337                     if (item != null) {
338                         layer.getHud().setTimeBarTime(item.mItemRef.mDateTakenInMs);
339                     }
340                 }
341             }
342         }
343     }
344
345     private void touchEnded(int posX, int posY, float timeElapsedx) {
346         if (mProcessTouch == false)
347             return;
348         int maxPixelsBeforeSwitch = mCamera.mWidth / 8;
349         mCamera.mConvergenceSpeed = 2.0f;
350         GridLayer layer = mLayer;
351         if (layer.getExpandedSlot() == Shared.INVALID && !layer.feedAboutToChange()) {
352             if (mCurrentSelectedSlot != Shared.INVALID) {
353                 if (layer.getState() == GridLayer.STATE_FULL_SCREEN) {
354                     if (!mTouchMoved) {
355                         // tap gesture for fullscreen
356                         if (layer.getZoomValue() == 1.0f)
357                             layer.changeFocusToSlot(mCurrentSelectedSlot, 1.0f);
358                     } else if (layer.getZoomValue() == 1.0f) {
359                         // we want to snap to a new slotIndex based on where the
360                         // current position is
361                         if (layer.inSlideShowMode()) {
362                             layer.endSlideshow();
363                         }
364                         float deltaX = posX - mFirstTouchPosX;
365                         float deltaY = posY - mFirstTouchPosY;
366                         if (deltaY != 0) {
367                             // it has moved vertically
368                         }
369                         layer.changeFocusToSlot(mCurrentSelectedSlot, 1.0f);
370                         HudLayer hud = layer.getHud();
371                         if (deltaX > maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
372                             layer.changeFocusToPreviousSlot(1.0f);
373                         } else if (deltaX < -maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
374                             layer.changeFocusToNextSlot(1.0f);
375                         }
376                     } else {
377                         // in zoomed state
378                         // we do nothing for now, but we should clamp to the
379                         // image bounds
380                         boolean hitEdge = layer.constrainCameraForSlot(mCurrentSelectedSlot);
381                         // mPrevHitEdge = false;
382                         if (hitEdge && mPrevHitEdge) {
383                             float deltaX = posX - mFirstTouchPosX;
384                             float deltaY = posY - mFirstTouchPosY;
385                             maxPixelsBeforeSwitch *= 4;
386                             if (deltaY != 0) {
387                                 // it has moved vertically
388                             }
389                             mPrevHitEdge = false;
390                             HudLayer hud = layer.getHud();
391                             if (deltaX > maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
392                                 layer.changeFocusToPreviousSlot(1.0f);
393                             } else if (deltaX < -maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
394                                 layer.changeFocusToNextSlot(1.0f);
395                             } else {
396                                 mPrevHitEdge = hitEdge;
397                             }
398                         } else {
399                             mPrevHitEdge = hitEdge;
400                         }
401                     }
402                 }
403             } else {
404                 if (!layer.feedAboutToChange() && layer.getZoomValue() == 1.0f) {
405                     constrainCamera(true);
406                 }
407             }
408         }
409         mCurrentFocusSlot = Shared.INVALID;
410         mCurrentFocusIsPressed = false;
411         mPrevTouchPosX = posX;
412         mPrevTouchPosY = posY;
413         mProcessTouch = false;
414     }
415
416     private void constrainCamera(boolean b) {
417         Pool<Vector3f> pool = mPool;
418         GridLayer layer = mLayer;
419         Vector3f firstPosition = pool.create();
420         Vector3f lastPosition = pool.create();
421         Vector3f deltaAnchorPosition = pool.create();
422         try {
423             deltaAnchorPosition.set(layer.getDeltaAnchorPosition());
424             GridCamera camera = mCamera;
425             LayoutInterface layout = layer.getLayoutInterface();
426             GridCameraManager.getSlotPositionForSlotIndex(0, camera, layout, deltaAnchorPosition, firstPosition);
427             int lastSlotIndex = 0;
428             IndexRange completeRange = layer.getCompleteRange();
429             synchronized (completeRange) {
430                 lastSlotIndex = completeRange.end;
431             }
432             GridCameraManager.getSlotPositionForSlotIndex(lastSlotIndex, camera, layout, deltaAnchorPosition, lastPosition);
433             camera.computeConstraints(true, (layer.getState() != GridLayer.STATE_FULL_SCREEN), firstPosition, lastPosition);
434         } finally {
435             pool.delete(firstPosition);
436             pool.delete(lastPosition);
437             pool.delete(deltaAnchorPosition);
438         }
439     }
440
441     public void clearSelection() {
442         mCurrentSelectedSlot = Shared.INVALID;
443     }
444
445     public void clearFocus() {
446         mCurrentFocusSlot = Shared.INVALID;
447     }
448
449     public boolean isFocusItemPressed() {
450         return mCurrentFocusIsPressed;
451     }
452
453     public void update(float timeElapsed) {
454         mDpadIgnoreTime += timeElapsed;
455     }
456
457     public void setCurrentFocusSlot(int slotId) {
458         mCurrentSelectedSlot = slotId;
459     }
460
461     public boolean onDown(MotionEvent e) {
462         // TODO Auto-generated method stub
463         return true;
464     }
465
466     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
467         if (mCurrentSelectedSlot == Shared.INVALID) {
468             mCamera.moveYTo(0);
469             mCamera.moveZTo(0);
470             mCamera.mConvergenceSpeed = 1.0f;
471             float normalizedVelocity = velocityX * mCamera.mOneByScale;
472             // mCamera.moveBy(-velocityX * mCamera.mOneByScale * 0.25f, 0, 0);
473             // constrainCamera(true);
474             IndexRange visibleRange = mLayer.getVisibleRange();
475             int numVisibleSlots = visibleRange.end - visibleRange.begin;
476             if (numVisibleSlots > 0) {
477                 float fastFlingVelocity = 20.0f;
478                 int slotsToSkip = (int) (numVisibleSlots * (-normalizedVelocity / fastFlingVelocity));
479                 int maxSlots = numVisibleSlots;
480                 if (slotsToSkip > maxSlots)
481                     slotsToSkip = maxSlots;
482                 if (slotsToSkip < -maxSlots)
483                     slotsToSkip = -maxSlots;
484                 if (Math.abs(slotsToSkip) <= 1) {
485                     if (velocityX > 0)
486                         slotsToSkip = -2;
487                     else if (velocityX < 0)
488                         slotsToSkip = 2;
489                 }
490                 int slotToGetTo = mLayer.getAnchorSlotIndex(GridLayer.ANCHOR_CENTER) + slotsToSkip;
491                 if (slotToGetTo < 0)
492                     slotToGetTo = 0;
493                 int lastSlot = mLayer.getCompleteRange().end;
494                 if (slotToGetTo > lastSlot)
495                     slotToGetTo = lastSlot;
496                 mLayer.centerCameraForSlot(slotToGetTo, 1.0f);
497             }
498             constrainCamera(true);
499             return true;
500         } else {
501             return false;
502         }
503     }
504
505     public void onLongPress(MotionEvent e) {
506         if (mLayer.getFeed() != null && mLayer.getFeed().isSingleImageMode()) {
507             HudLayer hud = mLayer.getHud();
508             hud.getPathBar().setHidden(true);
509             hud.getMenuBar().setHidden(true);
510             if (hud.getMode() != HudLayer.MODE_NORMAL)
511                 hud.setMode(HudLayer.MODE_NORMAL);
512         }
513         if (mCurrentFocusSlot != Shared.INVALID) {
514             vibrateLong();
515             GridLayer layer = mLayer;
516             if (layer.getState() == GridLayer.STATE_FULL_SCREEN) {
517                 layer.deselectAll();
518             }
519             HudLayer hud = layer.getHud();
520             hud.enterSelectionMode();
521             layer.addSlotToSelectedItems(mCurrentFocusSlot, true, true);
522         }
523     }
524
525     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
526         // TODO Auto-generated method stub
527         return false;
528     }
529
530     public void onShowPress(MotionEvent e) {
531         // TODO Auto-generated method stub
532
533     }
534
535     public boolean onSingleTapUp(MotionEvent e) {
536         GridLayer layer = mLayer;
537         int posX = (int) e.getX();
538         int posY = (int) e.getY();
539         if (mCurrentSelectedSlot != Shared.INVALID) {
540             // Fullscreen mode.
541             mCamera.mConvergenceSpeed = 2.0f;
542             int slotId = mCurrentSelectedSlot;
543             if (layer.getZoomValue() == 1.0f) {
544                 layer.centerCameraForSlot(slotId, 1.0f);
545             } else {
546                 layer.constrainCameraForSlot(slotId);
547             }
548             DisplayItem displayItem = layer.getDisplayItemForSlotId(slotId);
549             if (displayItem != null) {
550                 final MediaItem item = displayItem.mItemRef;
551                 int heightBy2 = mCamera.mHeight / 2;
552                 boolean posYInBounds = (Math.abs(posY - heightBy2) < 64);
553                 if (posX < 32 && posYInBounds) {
554                     layer.changeFocusToPreviousSlot(1.0f);
555                 } else if (posX > mCamera.mWidth - 32 && posYInBounds) {
556                     layer.changeFocusToNextSlot(1.0f);
557                 } else if (item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) {
558                     Utils.playVideo(mContext, item);
559                 } else {
560                     // We stop any slideshow.
561                     HudLayer hud = layer.getHud();
562                     if (layer.inSlideShowMode()) {
563                         layer.endSlideshow();
564                     } else {
565                         hud.setAlpha(1.0f - hud.getAlpha());
566                     }
567                     if (hud.getMode() == HudLayer.MODE_SELECT) {
568                         hud.setAlpha(1.0f);
569                     }
570                 }
571             }
572         } else {
573             int slotId = layer.getSlotIndexForScreenPosition(posX, posY);
574             if (slotId != Shared.INVALID) {
575                 HudLayer hud = layer.getHud();
576                 if (hud.getMode() == HudLayer.MODE_SELECT) {
577                     layer.addSlotToSelectedItems(slotId, true, true);
578                 } else {
579                     boolean centerCamera = (mCurrentSelectedSlot == Shared.INVALID) ? layer.tapGesture(slotId, false) : true;
580                     if (centerCamera) {
581                         // We check if this item is a video or not.
582                         selectSlot(slotId);
583                     }
584                 }
585             } else {
586                 int state = layer.getState();
587                 if (state != GridLayer.STATE_FULL_SCREEN && state != GridLayer.STATE_GRID_VIEW
588                         && layer.getHud().getMode() != HudLayer.MODE_SELECT) {
589                     slotId = layer.getMetadataSlotIndexForScreenPosition(posX, posY);
590                     if (slotId != Shared.INVALID) {
591                         layer.tapGesture(slotId, true);
592                     }
593                 }
594             }
595         }
596         return true;
597     }
598
599     private void selectSlot(int slotId) {
600         GridLayer layer = mLayer;
601         if (layer.getState() == GridLayer.STATE_GRID_VIEW) {
602             DisplayItem displayItem = layer.getDisplayItemForSlotId(slotId);
603             if (displayItem != null) {
604                 final MediaItem item = displayItem.mItemRef;
605                 if (layer.getPickIntent()) {
606                     // we need to return this item
607                     ((Gallery) mContext).getHandler().post(new Runnable() {
608                         public void run() {
609                             ((Gallery) mContext).launchCropperOrFinish(item);
610                         }
611                     });
612                     return;
613                 }
614                 if (item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) {
615                     Utils.playVideo(mContext, item);
616                 } else {
617                     mCurrentSelectedSlot = slotId;
618                     layer.endSlideshow();
619                     layer.setState(GridLayer.STATE_FULL_SCREEN);
620                     mCamera.mConvergenceSpeed = 2.0f;
621                     layer.getHud().fullscreenSelectionChanged(item, mCurrentSelectedSlot + 1, layer.getCompleteRange().end + 1);
622                 }
623             }
624         }
625     }
626
627     public boolean onDoubleTap(MotionEvent e) {
628         final GridLayer layer = mLayer;
629         if (layer.getState() == GridLayer.STATE_FULL_SCREEN && !mCamera.isZAnimating()) {
630             float posX = e.getX();
631             float posY = e.getY();
632             final Vector3f retVal = new Vector3f();
633             posX -= (mCamera.mWidth / 2);
634             posY -= (mCamera.mHeight / 2);
635             mCamera.convertToRelativeCameraSpace(posX, posY, 0, retVal);
636             if (layer.getZoomValue() == 1.0f) {
637                 layer.setZoomValue(3f);
638                 mCamera.update(0.001f);
639                 mCamera.moveBy(retVal.x, retVal.y, 0);
640                 layer.constrainCameraForSlot(mCurrentSelectedSlot);
641             } else {
642                 layer.setZoomValue(1.0f);
643             }
644             mCamera.mConvergenceSpeed = 2.0f;
645         } else {
646             return onSingleTapConfirmed(e);
647         }
648         return true;
649     }
650
651     public boolean onDoubleTapEvent(MotionEvent e) {
652         return false;
653     }
654
655     public boolean onSingleTapConfirmed(MotionEvent e) {
656         return false;
657     }
658
659     public boolean touchPressed() {
660         return mProcessTouch;
661     }
662
663     private void vibrateShort() {
664         // As per request by Google, this line disables vibration.
665         //mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
666     }
667
668     private void vibrateLong() {
669         //mView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
670     }
671 }