1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.cooliris.media; 18 19 import android.content.Context; 20 import android.hardware.Sensor; 21 import android.hardware.SensorEvent; 22 import android.os.SystemClock; 23 import android.view.GestureDetector; 24 import android.view.KeyEvent; 25 import android.view.MotionEvent; 26 27 import com.cooliris.app.App; 28 29 public final class GridInputProcessor implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, 30 ScaleGestureDetector.OnScaleGestureListener { 31 private int mCurrentFocusSlot; 32 private boolean mCurrentFocusIsPressed; 33 private int mCurrentSelectedSlot; 34 35 private float mPrevTiltValueLowPass; 36 private float mPrevShakeValueHighPass; 37 private float mShakeValue; 38 private int mTouchPosX; 39 private int mTouchPosY; 40 private int mActionCode; 41 private long mPrevTouchTime; 42 private float mFirstTouchPosX; 43 private float mFirstTouchPosY; 44 private float mPrevTouchPosX; 45 private float mPrevTouchPosY; 46 private float mTouchVelX; 47 private float mTouchVelY; 48 private boolean mProcessTouch; 49 private boolean mTouchMoved; 50 private float mDpadIgnoreTime = 0.0f; 51 private GridCamera mCamera; 52 private GridLayer mLayer; 53 private Context mContext; 54 private Pool<Vector3f> mPool; 55 private DisplayItem[] mDisplayItems; 56 private boolean mPrevHitEdge; 57 private boolean mTouchFeedbackDelivered; 58 private GestureDetector mGestureDetector; 59 private ScaleGestureDetector mScaleGestureDetector; 60 private boolean mZoomGesture; 61 private int mCurrentScaleSlot; 62 private float mScale; 63 64 public GridInputProcessor(Context context, GridCamera camera, GridLayer layer, RenderView view, Pool<Vector3f> pool, 65 DisplayItem[] displayItems) { 66 mPool = pool; 67 mCamera = camera; 68 mLayer = layer; 69 mCurrentFocusSlot = Shared.INVALID; 70 mCurrentSelectedSlot = Shared.INVALID; 71 mCurrentScaleSlot = Shared.INVALID; 72 mContext = context; 73 mDisplayItems = displayItems; 74 mGestureDetector = new GestureDetector(context, this); 75 mScaleGestureDetector = new ScaleGestureDetector(context, this); 76 mGestureDetector.setIsLongpressEnabled(true); 77 mZoomGesture = false; 78 mScale = 1.0f; 79 } 80 81 public int getCurrentFocusSlot() { 82 return mCurrentFocusSlot; 83 } 84 85 public int getCurrentSelectedSlot() { 86 return mCurrentSelectedSlot; 87 } 88 89 public int getCurrentScaledSlot() { 90 return mCurrentScaleSlot; 91 } 92 93 public void setCurrentSelectedSlot(int slot) { 94 mCurrentSelectedSlot = slot; 95 GridLayer layer = mLayer; 96 layer.setState(GridLayer.STATE_FULL_SCREEN); 97 mCamera.mConvergenceSpeed = 2.0f; 98 mCamera.mFriction = 0.0f; 99 DisplayItem displayItem = layer.getDisplayItemForSlotId(slot); 100 MediaItem item = null; 101 if (displayItem != null) 102 item = displayItem.mItemRef; 103 layer.getHud().fullscreenSelectionChanged(item, mCurrentSelectedSlot + 1, layer.getCompleteRange().end + 1); 104 } 105 106 public void onSensorChanged(RenderView view, SensorEvent event, int state) { 107 if (mZoomGesture) 108 return; 109 switch (event.sensor.getType()) { 110 case Sensor.TYPE_ACCELEROMETER: 111 float[] values = event.values; 112 float valueToUse = (mCamera.mWidth < mCamera.mHeight) ? values[0] : -values[1]; 113 float tiltValue = 0.8f * mPrevTiltValueLowPass + 0.2f * valueToUse; 114 if (Math.abs(tiltValue) < 0.5f) 115 tiltValue = 0.0f; 116 if (state == GridLayer.STATE_FULL_SCREEN) 117 tiltValue = 0.0f; 118 if (tiltValue != 0.0f) 119 view.requestRender(); 120 mCamera.mEyeOffsetX = -3.0f * tiltValue; 121 float shakeValue = values[1] * values[1] + values[2] * values[2]; 122 mShakeValue = shakeValue - mPrevShakeValueHighPass; 123 mPrevShakeValueHighPass = shakeValue; 124 if (mShakeValue < 16.0f) { 125 mShakeValue = 0; 126 } else { 127 mShakeValue = mShakeValue * 4.0f; 128 if (mShakeValue > 200) { 129 mShakeValue = 200; 130 } 131 } 132 break; 133 } 134 } 135 136 public boolean onTouchEvent(MotionEvent event) { 137 mTouchPosX = (int) (event.getX()); 138 mTouchPosY = (int) (event.getY()); 139 mActionCode = event.getAction(); 140 long timestamp = SystemClock.elapsedRealtime(); 141 long delta = timestamp - mPrevTouchTime; 142 mPrevTouchTime = timestamp; 143 float timeElapsed = (float) delta; 144 timeElapsed = timeElapsed * 0.001f; // division by 1000 for seconds 145 switch (mActionCode) { 146 case MotionEvent.ACTION_UP: 147 touchEnded(mTouchPosX, mTouchPosY, timeElapsed); 148 break; 149 case MotionEvent.ACTION_DOWN: 150 mPrevTouchTime = timestamp; 151 touchBegan(mTouchPosX, mTouchPosY); 152 break; 153 case MotionEvent.ACTION_MOVE: 154 touchMoved(mTouchPosX, mTouchPosY, timeElapsed); 155 break; 156 } 157 if (!mZoomGesture) 158 mGestureDetector.onTouchEvent(event); 159 mScaleGestureDetector.onTouchEvent(event); 160 return true; 161 } 162 163 public boolean onKeyDown(int keyCode, KeyEvent event, int state) { 164 GridLayer layer = mLayer; 165 if (keyCode == KeyEvent.KEYCODE_BACK) { 166 if (layer.getViewIntent()) 167 return false; 168 if (layer.getHud().getMode() == HudLayer.MODE_SELECT) { 169 layer.deselectAll(); 170 return true; 171 } 172 if (layer.inSlideShowMode()) { 173 layer.endSlideshow(); 174 layer.getHud().setAlpha(1.0f); 175 return true; 176 } 177 float zoomValue = layer.getZoomValue(); 178 if (zoomValue != 1.0f) { 179 layer.setZoomValue(1.0f); 180 layer.centerCameraForSlot(mCurrentSelectedSlot, 1.0f); 181 return true; 182 } 183 layer.goBack(); 184 if (state == GridLayer.STATE_MEDIA_SETS) 185 return false; 186 return true; 187 } 188 if (mDpadIgnoreTime < 0.1f) 189 return true; 190 mDpadIgnoreTime = 0.0f; 191 IndexRange bufferedVisibleRange = layer.getBufferedVisibleRange(); 192 int firstBufferedVisibleSlot = bufferedVisibleRange.begin; 193 int lastBufferedVisibleSlot = bufferedVisibleRange.end; 194 int anchorSlot = layer.getAnchorSlotIndex(GridLayer.ANCHOR_CENTER); 195 if (state == GridLayer.STATE_FULL_SCREEN) { 196 if (keyCode != KeyEvent.KEYCODE_VOLUME_UP && keyCode != KeyEvent.KEYCODE_VOLUME_DOWN 197 && keyCode != KeyEvent.KEYCODE_MUTE && keyCode != KeyEvent.KEYCODE_HEADSETHOOK 198 && keyCode != KeyEvent.KEYCODE_NOTIFICATION) { 199 layer.endSlideshow(); 200 } 201 boolean needsVibrate = false; 202 boolean directionalKeyPressed = false; 203 if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { 204 needsVibrate = !layer.changeFocusToNextSlot(1.0f); 205 directionalKeyPressed = true; 206 } 207 if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { 208 needsVibrate = !layer.changeFocusToPreviousSlot(1.0f); 209 directionalKeyPressed = true; 210 } 211 if (directionalKeyPressed) { 212 if (layer.getHud().getMode() == HudLayer.MODE_SELECT) { 213 layer.deselectAll(); 214 layer.enterSelectionMode(); 215 } 216 } 217 if (needsVibrate) { 218 vibrateShort(); 219 } 220 if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER && !mCamera.isAnimating()) { 221 if (layer.getZoomValue() == 1.0f) 222 layer.zoomInToSelectedItem(); 223 else 224 layer.setZoomValue(1.0f); 225 } 226 if (keyCode == KeyEvent.KEYCODE_MENU) { 227 if (mLayer.getFeed() != null && mLayer.getFeed().isSingleImageMode()) { 228 return true; 229 } 230 if (layer.getHud().getMode() == HudLayer.MODE_NORMAL) 231 layer.enterSelectionMode(); 232 else 233 layer.deselectAll(); 234 } 235 } else { 236 mCurrentFocusIsPressed = false; 237 int numRows = ((GridLayoutInterface) layer.getLayoutInterface()).mNumRows; 238 if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER && mCurrentFocusSlot != Shared.INVALID) { 239 if (layer.getHud().getMode() != HudLayer.MODE_SELECT) { 240 boolean centerCamera = layer.tapGesture(mCurrentFocusSlot, false); 241 if (centerCamera) { 242 int slotId = mCurrentFocusSlot; 243 selectSlot(slotId); 244 } 245 mCurrentFocusSlot = Shared.INVALID; 246 return true; 247 } else { 248 layer.addSlotToSelectedItems(mCurrentFocusSlot, true, true); 249 } 250 mCurrentFocusIsPressed = true; 251 } else if (keyCode == KeyEvent.KEYCODE_MENU && mCurrentFocusSlot != Shared.INVALID) { 252 if (layer.getHud().getMode() == HudLayer.MODE_NORMAL) 253 layer.enterSelectionMode(); 254 else 255 layer.deselectAll(); 256 } else if (mCurrentFocusSlot == Shared.INVALID) { 257 mCurrentFocusSlot = anchorSlot; 258 } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { 259 mCurrentFocusSlot += numRows; 260 } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { 261 mCurrentFocusSlot -= numRows; 262 } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { 263 --mCurrentFocusSlot; 264 } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { 265 ++mCurrentFocusSlot; 266 } 267 if (mCurrentFocusSlot > lastBufferedVisibleSlot) { 268 mCurrentFocusSlot = lastBufferedVisibleSlot; 269 } 270 if (mCurrentFocusSlot < firstBufferedVisibleSlot) 271 mCurrentFocusSlot = firstBufferedVisibleSlot; 272 if (mCurrentFocusSlot != Shared.INVALID) { 273 layer.centerCameraForSlot(mCurrentFocusSlot, 1.0f); 274 } 275 } 276 return false; 277 } 278 279 private void touchBegan(int posX, int posY) { 280 mPrevTouchPosX = posX; 281 mPrevTouchPosY = posY; 282 mFirstTouchPosX = posX; 283 mFirstTouchPosY = posY; 284 mTouchVelX = 0; 285 mTouchVelY = 0; 286 mProcessTouch = true; 287 mZoomGesture = false; 288 mTouchMoved = false; 289 mCamera.stopMovementInX(); 290 GridLayer layer = mLayer; 291 mCurrentFocusSlot = layer.getSlotIndexForScreenPosition(posX, posY); 292 mCurrentFocusIsPressed = true; 293 mTouchFeedbackDelivered = false; 294 HudLayer hud = layer.getHud(); 295 if (hud.getMode() == HudLayer.MODE_SELECT) 296 hud.closeSelectionMenu(); 297 if (layer.getState() == GridLayer.STATE_FULL_SCREEN && hud.getMode() == HudLayer.MODE_SELECT) { 298 layer.deselectAll(); 299 hud.setAlpha(1.0f); 300 } 301 int slotId = layer.getSlotIndexForScreenPosition(posX, posY); 302 if (slotId != Shared.INVALID && layer.getState() != GridLayer.STATE_FULL_SCREEN) { 303 vibrateShort(); 304 } 305 } 306 307 private void touchMoved(int posX, int posY, float timeElapsedx) { 308 if (mProcessTouch && !mZoomGesture) { 309 GridLayer layer = mLayer; 310 GridCamera camera = mCamera; 311 float deltaX = -(posX - mPrevTouchPosX); // negation since the wall 312 // moves in a direction 313 // opposite to that of 314 // the touch 315 float deltaY = -(posY - mPrevTouchPosY); 316 if (Math.abs(deltaX) >= 10.0f || Math.abs(deltaY) >= 10.0f) { 317 mTouchMoved = true; 318 } 319 Pool<Vector3f> pool = mPool; 320 Vector3f firstPosition = pool.create(); 321 Vector3f lastPosition = pool.create(); 322 Vector3f deltaAnchorPosition = pool.create(); 323 Vector3f worldPosDelta = pool.create(); 324 try { 325 deltaAnchorPosition.set(layer.getDeltaAnchorPosition()); 326 LayoutInterface layout = layer.getLayoutInterface(); 327 GridCameraManager.getSlotPositionForSlotIndex(0, camera, layout, deltaAnchorPosition, firstPosition); 328 int lastSlotIndex = 0; 329 IndexRange completeRange = layer.getCompleteRange(); 330 synchronized (completeRange) { 331 lastSlotIndex = completeRange.end; 332 } 333 GridCameraManager.getSlotPositionForSlotIndex(lastSlotIndex, camera, layout, deltaAnchorPosition, lastPosition); 334 335 camera.convertToRelativeCameraSpace(deltaX, deltaY, 0, worldPosDelta); 336 deltaX = worldPosDelta.x; 337 deltaY = worldPosDelta.y; 338 camera.moveBy(deltaX, (layer.getZoomValue() == 1.0f) ? 0 : deltaY, 0); 339 deltaX *= camera.mScale; 340 deltaY *= camera.mScale; 341 } finally { 342 pool.delete(firstPosition); 343 pool.delete(lastPosition); 344 pool.delete(deltaAnchorPosition); 345 pool.delete(worldPosDelta); 346 } 347 if (layer.getZoomValue() == 1.0f) { 348 if (camera 349 .computeConstraints(false, (layer.getState() != GridLayer.STATE_FULL_SCREEN), firstPosition, lastPosition)) { 350 deltaX = 0.0f; 351 // vibrate 352 if (!mTouchFeedbackDelivered) { 353 mTouchFeedbackDelivered = true; 354 vibrateLong(); 355 } 356 } 357 } 358 mTouchVelX = deltaX * timeElapsedx; 359 mTouchVelY = deltaY * timeElapsedx; 360 float maxVelXx = (mCamera.mWidth * 0.5f); 361 float maxVelYx = (mCamera.mHeight); 362 mTouchVelX = FloatUtils.clamp(mTouchVelX, -maxVelXx, maxVelXx); 363 mTouchVelY = FloatUtils.clamp(mTouchVelY, -maxVelYx, maxVelYx); 364 mPrevTouchPosX = posX; 365 mPrevTouchPosY = posY; 366 // you want the movement to track the finger immediately 367 if (mTouchMoved == false) 368 mCurrentFocusSlot = layer.getSlotIndexForScreenPosition(posX, posY); 369 else 370 mCurrentFocusSlot = Shared.INVALID; 371 if (!mCamera.isZAnimating()) { 372 mCamera.commitMoveInX(); 373 mCamera.commitMoveInY(); 374 } 375 int anchorSlotIndex = layer.getAnchorSlotIndex(GridLayer.ANCHOR_LEFT); 376 DisplayItem[] displayItems = mDisplayItems; 377 IndexRange bufferedVisibleRange = layer.getBufferedVisibleRange(); 378 int firstBufferedVisibleSlot = bufferedVisibleRange.begin; 379 int lastBufferedVisibleSlot = bufferedVisibleRange.end; 380 synchronized (displayItems) { 381 if (anchorSlotIndex >= firstBufferedVisibleSlot && anchorSlotIndex <= lastBufferedVisibleSlot) { 382 DisplayItem item = displayItems[(anchorSlotIndex - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; 383 if (item != null) { 384 layer.getHud().setTimeBarTime(item.mItemRef.mDateTakenInMs); 385 } 386 } 387 } 388 } 389 } 390 391 private void touchEnded(int posX, int posY, float timeElapsedx) { 392 if (mProcessTouch == false || mZoomGesture) { 393 return; 394 } 395 int maxPixelsBeforeSwitch = mCamera.mWidth / 8; 396 mCamera.mConvergenceSpeed = 2.0f; 397 GridLayer layer = mLayer; 398 if (layer.getExpandedSlot() == Shared.INVALID && !layer.feedAboutToChange() && !mZoomGesture) { 399 if (mCurrentSelectedSlot != Shared.INVALID) { 400 if (layer.getState() == GridLayer.STATE_FULL_SCREEN) { 401 if (!mTouchMoved) { 402 // tap gesture for fullscreen 403 if (layer.getZoomValue() == 1.0f) 404 layer.changeFocusToSlot(mCurrentSelectedSlot, 1.0f); 405 } else if (layer.getZoomValue() == 1.0f) { 406 // we want to snap to a new slotIndex based on where the 407 // current position is 408 if (layer.inSlideShowMode()) { 409 layer.endSlideshow(); 410 } 411 float deltaX = posX - mFirstTouchPosX; 412 float deltaY = posY - mFirstTouchPosY; 413 if (deltaY != 0) { 414 // it has moved vertically 415 } 416 layer.changeFocusToSlot(mCurrentSelectedSlot, 1.0f); 417 HudLayer hud = layer.getHud(); 418 if (deltaX > maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) { 419 layer.changeFocusToPreviousSlot(1.0f); 420 } else if (deltaX < -maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) { 421 layer.changeFocusToNextSlot(1.0f); 422 } 423 } else { 424 // in zoomed state 425 // we do nothing for now, but we should clamp to the 426 // image bounds 427 boolean hitEdge = layer.constrainCameraForSlot(mCurrentSelectedSlot); 428 // mPrevHitEdge = false; 429 if (hitEdge && mPrevHitEdge) { 430 float deltaX = posX - mFirstTouchPosX; 431 float deltaY = posY - mFirstTouchPosY; 432 maxPixelsBeforeSwitch *= 4; 433 if (deltaY != 0) { 434 // it has moved vertically 435 } 436 mPrevHitEdge = false; 437 HudLayer hud = layer.getHud(); 438 if (deltaX > maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) { 439 layer.changeFocusToPreviousSlot(1.0f); 440 } else if (deltaX < -maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) { 441 layer.changeFocusToNextSlot(1.0f); 442 } else { 443 mPrevHitEdge = hitEdge; 444 } 445 } else { 446 mPrevHitEdge = hitEdge; 447 } 448 } 449 } 450 } else { 451 if (!layer.feedAboutToChange() && layer.getZoomValue() == 1.0f && mTouchMoved) { 452 constrainCamera(true); 453 } 454 } 455 } 456 mCurrentFocusSlot = Shared.INVALID; 457 mCurrentFocusIsPressed = false; 458 mPrevTouchPosX = posX; 459 mPrevTouchPosY = posY; 460 mProcessTouch = false; 461 } 462 463 private void constrainCamera(boolean b) { 464 Pool<Vector3f> pool = mPool; 465 GridLayer layer = mLayer; 466 Vector3f firstPosition = pool.create(); 467 Vector3f lastPosition = pool.create(); 468 Vector3f deltaAnchorPosition = pool.create(); 469 try { 470 deltaAnchorPosition.set(layer.getDeltaAnchorPosition()); 471 GridCamera camera = mCamera; 472 LayoutInterface layout = layer.getLayoutInterface(); 473 GridCameraManager.getSlotPositionForSlotIndex(0, camera, layout, deltaAnchorPosition, firstPosition); 474 int lastSlotIndex = 0; 475 IndexRange completeRange = layer.getCompleteRange(); 476 synchronized (completeRange) { 477 lastSlotIndex = completeRange.end; 478 } 479 GridCameraManager.getSlotPositionForSlotIndex(lastSlotIndex, camera, layout, deltaAnchorPosition, lastPosition); 480 camera.computeConstraints(true, (layer.getState() != GridLayer.STATE_FULL_SCREEN), firstPosition, lastPosition); 481 } finally { 482 pool.delete(firstPosition); 483 pool.delete(lastPosition); 484 pool.delete(deltaAnchorPosition); 485 } 486 } 487 488 public void clearSelection() { 489 mCurrentSelectedSlot = Shared.INVALID; 490 } 491 492 public void clearFocus() { 493 mCurrentFocusSlot = Shared.INVALID; 494 } 495 496 public boolean isFocusItemPressed() { 497 return mCurrentFocusIsPressed; 498 } 499 500 public void update(float timeElapsed) { 501 mDpadIgnoreTime += timeElapsed; 502 if (mCamera.mFriction != 0.0f) { 503 constrainCamera(true); 504 } 505 } 506 507 public void setCurrentFocusSlot(int slotId) { 508 mCurrentSelectedSlot = slotId; 509 } 510 511 public boolean onDown(MotionEvent e) { 512 // TODO Auto-generated method stub 513 return true; 514 } 515 516 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 517 if (mCurrentSelectedSlot == Shared.INVALID) { 518 mCamera.moveYTo(0); 519 mCamera.moveZTo(0); 520 mCamera.mConvergenceSpeed = 1.0f; 521 mCamera.mFriction = 0.0f; 522 float normalizedVelocity = velocityX * mCamera.mOneByScale; 523 // mCamera.moveBy(-velocityX * mCamera.mOneByScale * 0.25f, 0, 0); 524 // constrainCamera(true); 525 IndexRange visibleRange = mLayer.getVisibleRange(); 526 int numVisibleSlots = visibleRange.end - visibleRange.begin; 527 if (numVisibleSlots > 0) { 528 float fastFlingVelocity = 10.0f; 529 int slotsToSkip = (int) (numVisibleSlots * (-normalizedVelocity / fastFlingVelocity)); 530 int maxSlots = numVisibleSlots; 531 if (slotsToSkip > maxSlots) 532 slotsToSkip = maxSlots; 533 if (slotsToSkip < -maxSlots) 534 slotsToSkip = -maxSlots; 535 if (Math.abs(slotsToSkip) <= 1) { 536 if (velocityX > 0) 537 slotsToSkip = -2; 538 else if (velocityX < 0) 539 slotsToSkip = 2; 540 } 541 int slotToGetTo = mLayer.getAnchorSlotIndex(GridLayer.ANCHOR_CENTER) + slotsToSkip; 542 if (slotToGetTo < 0) 543 slotToGetTo = 0; 544 int lastSlot = mLayer.getCompleteRange().end; 545 if (slotToGetTo > lastSlot) 546 slotToGetTo = lastSlot; 547 mLayer.centerCameraForSlot(slotToGetTo, 1.0f); 548 } 549 constrainCamera(true); 550 return true; 551 } else { 552 return false; 553 } 554 } 555 556 public void onLongPress(MotionEvent e) { 557 if (mZoomGesture) 558 return; 559 if (mLayer.getFeed() != null && mLayer.getFeed().isSingleImageMode()) { 560 HudLayer hud = mLayer.getHud(); 561 hud.getPathBar().setHidden(true); 562 hud.getMenuBar().setHidden(true); 563 if (hud.getMode() != HudLayer.MODE_NORMAL) 564 hud.setMode(HudLayer.MODE_NORMAL); 565 } 566 if (mCurrentFocusSlot != Shared.INVALID) { 567 vibrateLong(); 568 GridLayer layer = mLayer; 569 if (layer.getState() == GridLayer.STATE_FULL_SCREEN) { 570 layer.deselectAll(); 571 } 572 HudLayer hud = layer.getHud(); 573 hud.enterSelectionMode(); 574 layer.addSlotToSelectedItems(mCurrentFocusSlot, true, true); 575 } 576 } 577 578 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 579 // TODO Auto-generated method stub 580 return false; 581 } 582 583 public void onShowPress(MotionEvent e) { 584 // TODO Auto-generated method stub 585 586 } 587 588 public boolean onSingleTapUp(MotionEvent e) { 589 GridLayer layer = mLayer; 590 int posX = (int) e.getX(); 591 int posY = (int) e.getY(); 592 if (mCurrentSelectedSlot != Shared.INVALID) { 593 // Fullscreen mode. 594 mCamera.mConvergenceSpeed = 2.0f; 595 mCamera.mFriction = 0.0f; 596 int slotId = mCurrentSelectedSlot; 597 if (layer.getZoomValue() == 1.0f) { 598 layer.centerCameraForSlot(slotId, 1.0f); 599 } else { 600 layer.constrainCameraForSlot(slotId); 601 } 602 DisplayItem displayItem = layer.getDisplayItemForSlotId(slotId); 603 if (displayItem != null) { 604 final MediaItem item = displayItem.mItemRef; 605 int heightBy2 = mCamera.mHeight / 2; 606 boolean posYInBounds = (Math.abs(posY - heightBy2) < 64); 607 if (posX < 32 && posYInBounds) { 608 layer.changeFocusToPreviousSlot(1.0f); 609 } else if (posX > mCamera.mWidth - 32 && posYInBounds) { 610 layer.changeFocusToNextSlot(1.0f); 611 } else if (item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) { 612 Utils.playVideo(mContext, item); 613 } else { 614 // We stop any slideshow. 615 HudLayer hud = layer.getHud(); 616 if (layer.inSlideShowMode()) { 617 layer.endSlideshow(); 618 } else { 619 hud.setAlpha(1.0f - hud.getAlpha()); 620 } 621 if (hud.getMode() == HudLayer.MODE_SELECT) { 622 hud.setAlpha(1.0f); 623 } 624 } 625 } 626 } else { 627 int slotId = layer.getSlotIndexForScreenPosition(posX, posY); 628 if (slotId != Shared.INVALID) { 629 HudLayer hud = layer.getHud(); 630 if (hud.getMode() == HudLayer.MODE_SELECT) { 631 layer.addSlotToSelectedItems(slotId, true, true); 632 } else { 633 boolean centerCamera = (mCurrentSelectedSlot == Shared.INVALID) ? layer.tapGesture(slotId, false) : true; 634 if (centerCamera) { 635 // We check if this item is a video or not. 636 selectSlot(slotId); 637 } 638 } 639 } else { 640 int state = layer.getState(); 641 if (state != GridLayer.STATE_FULL_SCREEN && state != GridLayer.STATE_GRID_VIEW 642 && layer.getHud().getMode() != HudLayer.MODE_SELECT) { 643 slotId = layer.getMetadataSlotIndexForScreenPosition(posX, posY); 644 if (slotId != Shared.INVALID) { 645 layer.tapGesture(slotId, true); 646 } 647 } 648 } 649 } 650 return true; 651 } 652 653 private void selectSlot(int slotId) { 654 GridLayer layer = mLayer; 655 if (layer.getState() == GridLayer.STATE_GRID_VIEW) { 656 DisplayItem displayItem = layer.getDisplayItemForSlotId(slotId); 657 if (displayItem != null) { 658 final MediaItem item = displayItem.mItemRef; 659 if (layer.getPickIntent()) { 660 // we need to return this item 661 App.get(mContext).getHandler().post(new Runnable() { 662 public void run() { 663 CropImage.launchCropperOrFinish(mContext, item); 664 } 665 }); 666 return; 667 } 668 if (item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) { 669 Utils.playVideo(mContext, item); 670 } else { 671 mCurrentSelectedSlot = slotId; 672 layer.endSlideshow(); 673 layer.setState(GridLayer.STATE_FULL_SCREEN); 674 mCamera.mConvergenceSpeed = 2.0f; 675 mCamera.mFriction = 0.0f; 676 layer.getHud().fullscreenSelectionChanged(item, mCurrentSelectedSlot + 1, layer.getCompleteRange().end + 1); 677 } 678 } 679 } 680 constrainCamera(true); 681 } 682 683 public boolean onDoubleTap(MotionEvent e) { 684 final GridLayer layer = mLayer; 685 if (layer.getState() == GridLayer.STATE_FULL_SCREEN && !mCamera.isZAnimating()) { 686 float posX = e.getX(); 687 float posY = e.getY(); 688 final Vector3f retVal = new Vector3f(); 689 posX -= (mCamera.mWidth / 2); 690 posY -= (mCamera.mHeight / 2); 691 mCamera.convertToRelativeCameraSpace(posX, posY, 0, retVal); 692 if (layer.getZoomValue() == 1.0f) { 693 layer.setZoomValue(3f); 694 mCamera.update(0.001f); 695 mCamera.moveBy(retVal.x, retVal.y, 0); 696 layer.constrainCameraForSlot(mCurrentSelectedSlot); 697 } else { 698 layer.setZoomValue(1.0f); 699 } 700 mCamera.mConvergenceSpeed = 2.0f; 701 mCamera.mFriction = 0.0f; 702 } else { 703 return onSingleTapConfirmed(e); 704 } 705 return true; 706 } 707 708 public boolean onDoubleTapEvent(MotionEvent e) { 709 return false; 710 } 711 712 public boolean onSingleTapConfirmed(MotionEvent e) { 713 return false; 714 } 715 716 public boolean touchPressed() { 717 return mProcessTouch; 718 } 719 720 private void vibrateShort() { 721 // As per request by Google, this line disables vibration. 722 // mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 723 } 724 725 private void vibrateLong() { 726 // mView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); 727 } 728 729 public boolean onScale(ScaleGestureDetector detector) { 730 final GridLayer layer = mLayer; 731 float scale = detector.getScaleFactor(); 732 if (Float.isInfinite(scale) || Float.isNaN(scale)) 733 return true; 734 mScale = scale * mScale; 735 boolean performTranslation = Math.abs(scale - 1.0f) < 0.001f ? false : true; 736 if (layer.getState() == GridLayer.STATE_FULL_SCREEN) { 737 float currentScale = layer.getZoomValue(); 738 if (currentScale <= 1.0f) 739 performTranslation = false; 740 final Vector3f retVal = new Vector3f(); 741 if (performTranslation) { 742 float posX = detector.getFocusX(); 743 float posY = detector.getFocusY(); 744 posX -= (mCamera.mWidth / 2); 745 posY -= (mCamera.mHeight / 2); 746 mCamera.convertToRelativeCameraSpace(posX, posY, 0, retVal); 747 } 748 if (currentScale < 0.7f && scale < 1.0f) { 749 scale = 1.0f; 750 } 751 if (currentScale > 8.0f && scale > 1.0f) { 752 scale = 1.0f; 753 } 754 layer.setZoomValue(currentScale * scale); 755 if (performTranslation) { 756 mCamera.update(0.001f); 757 mCamera.moveBy(retVal.x, retVal.y, 0); 758 layer.constrainCameraForSlot(mCurrentSelectedSlot); 759 } 760 } 761 if (mLayer.getState() == GridLayer.STATE_GRID_VIEW) { 762 mCurrentScaleSlot = Shared.INVALID; 763 mCurrentFocusSlot = Shared.INVALID; 764 } 765 return true; 766 } 767 768 public boolean onScaleBegin(ScaleGestureDetector detector) { 769 mZoomGesture = true; 770 mScale = 1.0f; 771 mLayer.getHud().hideZoomButtons(true); 772 int posX = (int) detector.getFocusX(); 773 int posY = (int) detector.getFocusY(); 774 int slotId = mLayer.getSlotIndexForScreenPosition(posX, posY); 775 if (slotId == Shared.INVALID) { 776 slotId = mLayer.getAnchorSlotIndex(GridLayer.ANCHOR_CENTER); 777 } 778 if (slotId != Shared.INVALID) { 779 mCurrentScaleSlot = slotId; 780 mCurrentFocusSlot = slotId; 781 } 782 if (mLayer.getState() == GridLayer.STATE_GRID_VIEW) { 783 mCurrentScaleSlot = Shared.INVALID; 784 mCurrentFocusSlot = Shared.INVALID; 785 } 786 constrainCamera(true); 787 return true; 788 } 789 790 public void onScaleEnd(ScaleGestureDetector detector, boolean cancel) { 791 if (!cancel) { 792 final GridLayer layer = mLayer; 793 if (layer.getState() == GridLayer.STATE_FULL_SCREEN) { 794 float currentScale = layer.getZoomValue(); 795 if (currentScale < 1.0f) { 796 currentScale = 1.0f; 797 } else if (currentScale > 6.0f) { 798 currentScale = 6.0f; 799 } 800 if (currentScale != layer.getZoomValue()) { 801 layer.setZoomValue(currentScale); 802 } 803 layer.constrainCameraForSlot(mCurrentSelectedSlot); 804 mLayer.getHud().hideZoomButtons(false); 805 if (mScale < 0.7f && false) { 806 layer.goBack(); 807 } 808 } else { 809 if (mScale > 3.0f && false) { 810 HudLayer hud = layer.getHud(); 811 if (hud.getMode() == HudLayer.MODE_SELECT) { 812 layer.addSlotToSelectedItems(mCurrentScaleSlot, true, true); 813 } else { 814 boolean centerCamera = (mCurrentSelectedSlot == Shared.INVALID) ? layer 815 .tapGesture(mCurrentScaleSlot, false) : true; 816 if (centerCamera) { 817 // We check if this item is a video or not. 818 selectSlot(mCurrentScaleSlot); 819 } 820 } 821 } else { 822 if (layer.getState() == GridLayer.STATE_GRID_VIEW) { 823 if (mScale < 0.7f && false) { 824 layer.goBack(); 825 } 826 } 827 } 828 } 829 } else { 830 // The gesture was cancelled. 831 final GridLayer layer = mLayer; 832 if (layer.getState() == GridLayer.STATE_FULL_SCREEN) { 833 layer.setZoomValue(1.0f); 834 mLayer.getHud().hideZoomButtons(false); 835 } 836 } 837 resetScale(); 838 } 839 840 public float getScale() { 841 return mScale; 842 } 843 844 public void resetScale() { 845 mScale = 1.0f; 846 mCurrentScaleSlot = Shared.INVALID; 847 } 848 849 public ScaleGestureDetector getScaleGestureDetector() { 850 return mScaleGestureDetector; 851 } 852 } 853