AlbumPage.java revision 2daced6baacd59850e7c64ea02f2479530654ed8
1/* 2 * Copyright (C) 2010 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 17package com.android.gallery3d.app; 18 19import android.app.Activity; 20import android.content.Context; 21import android.content.Intent; 22import android.graphics.Rect; 23import android.net.Uri; 24import android.os.Bundle; 25import android.os.Handler; 26import android.os.Message; 27import android.os.Vibrator; 28import android.provider.MediaStore; 29import android.view.Menu; 30import android.view.MenuInflater; 31import android.view.MenuItem; 32import android.widget.Toast; 33 34import com.android.gallery3d.R; 35import com.android.gallery3d.common.Utils; 36import com.android.gallery3d.data.DataManager; 37import com.android.gallery3d.data.MediaDetails; 38import com.android.gallery3d.data.MediaItem; 39import com.android.gallery3d.data.MediaObject; 40import com.android.gallery3d.data.MediaSet; 41import com.android.gallery3d.data.MtpDevice; 42import com.android.gallery3d.data.Path; 43import com.android.gallery3d.ui.ActionModeHandler; 44import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener; 45import com.android.gallery3d.ui.AlbumSlotRenderer; 46import com.android.gallery3d.ui.DetailsHelper; 47import com.android.gallery3d.ui.DetailsHelper.CloseListener; 48import com.android.gallery3d.ui.FadeTexture; 49import com.android.gallery3d.ui.GLCanvas; 50import com.android.gallery3d.ui.GLRoot; 51import com.android.gallery3d.ui.GLView; 52import com.android.gallery3d.ui.PhotoFallbackEffect; 53import com.android.gallery3d.ui.RelativePosition; 54import com.android.gallery3d.ui.SelectionManager; 55import com.android.gallery3d.ui.SlotView; 56import com.android.gallery3d.ui.SynchronizedHandler; 57import com.android.gallery3d.util.Future; 58import com.android.gallery3d.util.GalleryUtils; 59import com.android.gallery3d.util.MediaSetUtils; 60 61public class AlbumPage extends ActivityState implements GalleryActionBar.ClusterRunner, 62 SelectionManager.SelectionListener, MediaSet.SyncListener, GalleryActionBar.OnAlbumModeSelectedListener { 63 @SuppressWarnings("unused") 64 private static final String TAG = "AlbumPage"; 65 66 public static final String KEY_MEDIA_PATH = "media-path"; 67 public static final String KEY_PARENT_MEDIA_PATH = "parent-media-path"; 68 public static final String KEY_SET_CENTER = "set-center"; 69 public static final String KEY_AUTO_SELECT_ALL = "auto-select-all"; 70 public static final String KEY_SHOW_CLUSTER_MENU = "cluster-menu"; 71 public static final String KEY_EMPTY_ALBUM = "empty-album"; 72 public static final String KEY_RESUME_ANIMATION = "resume_animation"; 73 74 private static final int REQUEST_SLIDESHOW = 1; 75 public static final int REQUEST_PHOTO = 2; 76 private static final int REQUEST_DO_ANIMATION = 3; 77 78 private static final int BIT_LOADING_RELOAD = 1; 79 private static final int BIT_LOADING_SYNC = 2; 80 81 private static final float USER_DISTANCE_METER = 0.3f; 82 83 private boolean mIsActive = false; 84 private AlbumSlotRenderer mAlbumView; 85 private Path mMediaSetPath; 86 private String mParentMediaSetString; 87 private SlotView mSlotView; 88 89 private AlbumDataLoader mAlbumDataAdapter; 90 91 protected SelectionManager mSelectionManager; 92 private Vibrator mVibrator; 93 94 private boolean mGetContent; 95 private boolean mShowClusterMenu; 96 97 private ActionModeHandler mActionModeHandler; 98 private int mFocusIndex = 0; 99 private DetailsHelper mDetailsHelper; 100 private MyDetailsSource mDetailsSource; 101 private MediaSet mMediaSet; 102 private boolean mShowDetails; 103 private float mUserDistance; // in pixel 104 private Future<Integer> mSyncTask = null; 105 private boolean mLaunchedFromPhotoPage; 106 private boolean mInCameraApp; 107 private boolean mInCameraAndWantQuitOnPause; 108 109 private int mLoadingBits = 0; 110 private boolean mInitialSynced = false; 111 private RelativePosition mOpenCenter = new RelativePosition(); 112 113 private Handler mHandler; 114 private static final int MSG_PICK_PHOTO = 0; 115 116 private PhotoFallbackEffect mResumeEffect; 117 private PhotoFallbackEffect.PositionProvider mPositionProvider = 118 new PhotoFallbackEffect.PositionProvider() { 119 @Override 120 public Rect getPosition(int index) { 121 Rect rect = mSlotView.getSlotRect(index); 122 Rect bounds = mSlotView.bounds(); 123 rect.offset(bounds.left - mSlotView.getScrollX(), 124 bounds.top - mSlotView.getScrollY()); 125 return rect; 126 } 127 128 @Override 129 public int getItemIndex(Path path) { 130 int start = mSlotView.getVisibleStart(); 131 int end = mSlotView.getVisibleEnd(); 132 for (int i = start; i < end; ++i) { 133 MediaItem item = mAlbumDataAdapter.get(i); 134 if (item != null && item.getPath() == path) return i; 135 } 136 return -1; 137 } 138 }; 139 140 @Override 141 protected int getBackgroundColorId() { 142 return R.color.album_background; 143 } 144 145 private final GLView mRootPane = new GLView() { 146 private final float mMatrix[] = new float[16]; 147 148 @Override 149 protected void onLayout( 150 boolean changed, int left, int top, int right, int bottom) { 151 152 int slotViewTop = mActivity.getGalleryActionBar().getHeight(); 153 int slotViewBottom = bottom - top; 154 int slotViewRight = right - left; 155 156 if (mShowDetails) { 157 mDetailsHelper.layout(left, slotViewTop, right, bottom); 158 } else { 159 mAlbumView.setHighlightItemPath(null); 160 } 161 162 // Set the mSlotView as a reference point to the open animation 163 mOpenCenter.setReferencePosition(0, slotViewTop); 164 mSlotView.layout(0, slotViewTop, slotViewRight, slotViewBottom); 165 GalleryUtils.setViewPointMatrix(mMatrix, 166 (right - left) / 2, (bottom - top) / 2, -mUserDistance); 167 } 168 169 @Override 170 protected void render(GLCanvas canvas) { 171 canvas.save(GLCanvas.SAVE_FLAG_MATRIX); 172 canvas.multiplyMatrix(mMatrix, 0); 173 super.render(canvas); 174 175 if (mResumeEffect != null) { 176 boolean more = mResumeEffect.draw(canvas); 177 if (!more) { 178 mResumeEffect = null; 179 mAlbumView.setSlotFilter(null); 180 } 181 // We want to render one more time even when no more effect 182 // required. So that the animated thumbnails could be draw 183 // with declarations in super.render(). 184 invalidate(); 185 } 186 canvas.restore(); 187 } 188 }; 189 190 // This are the transitions we want: 191 // 192 // +--------+ +------------+ +-------+ +----------+ 193 // | Camera |---------->| Fullscreen |--->| Album |--->| AlbumSet | 194 // | View | thumbnail | Photo | up | Page | up | Page | 195 // +--------+ +------------+ +-------+ +----------+ 196 // ^ | | ^ | 197 // | | | | | close 198 // +----------back--------+ +----back----+ +--back-> app 199 // 200 @Override 201 protected void onBackPressed() { 202 if (mShowDetails) { 203 hideDetails(); 204 } else if (mSelectionManager.inSelectionMode()) { 205 mSelectionManager.leaveSelectionMode(); 206 } else { 207 if(mLaunchedFromPhotoPage) { 208 mActivity.getTransitionStore().putIfNotPresent( 209 PhotoPage.KEY_ALBUMPAGE_TRANSITION, 210 PhotoPage.MSG_ALBUMPAGE_RESUMED); 211 } 212 // TODO: fix this regression 213 // mAlbumView.savePositions(PositionRepository.getInstance(mActivity)); 214 if (mInCameraApp) { 215 super.onBackPressed(); 216 } else { 217 onUpPressed(); 218 } 219 } 220 } 221 222 private void onUpPressed() { 223 if (mInCameraApp) { 224 GalleryUtils.startGalleryActivity(mActivity); 225 } else if (mActivity.getStateManager().getStateCount() > 1) { 226 super.onBackPressed(); 227 } else if (mParentMediaSetString != null) { 228 Bundle data = new Bundle(getData()); 229 data.putString(AlbumSetPage.KEY_MEDIA_PATH, mParentMediaSetString); 230 mActivity.getStateManager().switchState( 231 this, AlbumSetPage.class, data); 232 } 233 } 234 235 private void onDown(int index) { 236 mAlbumView.setPressedIndex(index); 237 } 238 239 private void onUp(boolean followedByLongPress) { 240 if (followedByLongPress) { 241 // Avoid showing press-up animations for long-press. 242 mAlbumView.setPressedIndex(-1); 243 } else { 244 mAlbumView.setPressedUp(); 245 } 246 } 247 248 private void onSingleTapUp(int slotIndex) { 249 if (!mIsActive) return; 250 251 if (mSelectionManager.inSelectionMode()) { 252 MediaItem item = mAlbumDataAdapter.get(slotIndex); 253 if (item == null) return; // Item not ready yet, ignore the click 254 mSelectionManager.toggle(item.getPath()); 255 mSlotView.invalidate(); 256 } else { 257 // Render transition in pressed state 258 mAlbumView.setPressedIndex(slotIndex); 259 mAlbumView.setPressedUp(); 260 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_PHOTO, slotIndex, 0), 261 FadeTexture.DURATION); 262 } 263 } 264 265 private void pickPhoto(int slotIndex) { 266 pickPhoto(slotIndex, false); 267 } 268 269 private void pickPhoto(int slotIndex, boolean startInFilmstrip) { 270 if (!mIsActive) return; 271 272 if (!startInFilmstrip) { 273 // Launch photos in lights out mode 274 mActivity.getGLRoot().setLightsOutMode(true); 275 } 276 277 MediaItem item = mAlbumDataAdapter.get(slotIndex); 278 if (item == null) return; // Item not ready yet, ignore the click 279 if (mGetContent) { 280 onGetContent(item); 281 } else if (mLaunchedFromPhotoPage) { 282 TransitionStore transitions = mActivity.getTransitionStore(); 283 transitions.put( 284 PhotoPage.KEY_ALBUMPAGE_TRANSITION, 285 PhotoPage.MSG_ALBUMPAGE_PICKED); 286 transitions.put(PhotoPage.KEY_INDEX_HINT, slotIndex); 287 onBackPressed(); 288 } else { 289 // Get into the PhotoPage. 290 // mAlbumView.savePositions(PositionRepository.getInstance(mActivity)); 291 Bundle data = new Bundle(); 292 data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex); 293 data.putParcelable(PhotoPage.KEY_OPEN_ANIMATION_RECT, 294 mSlotView.getSlotRect(slotIndex, mRootPane)); 295 data.putString(PhotoPage.KEY_MEDIA_SET_PATH, 296 mMediaSetPath.toString()); 297 data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, 298 item.getPath().toString()); 299 data.putInt(PhotoPage.KEY_ALBUMPAGE_TRANSITION, 300 PhotoPage.MSG_ALBUMPAGE_STARTED); 301 data.putBoolean(PhotoPage.KEY_START_IN_FILMSTRIP, 302 startInFilmstrip); 303 data.putBoolean(PhotoPage.KEY_IN_CAMERA_ROLL, mMediaSet.isCameraRoll()); 304 if (startInFilmstrip) { 305 mActivity.getStateManager().switchState(this, PhotoPage.class, data); 306 } else { 307 mActivity.getStateManager().startStateForResult( 308 PhotoPage.class, REQUEST_PHOTO, data); 309 } 310 } 311 } 312 313 private void onGetContent(final MediaItem item) { 314 DataManager dm = mActivity.getDataManager(); 315 Activity activity = mActivity; 316 if (mData.getString(Gallery.EXTRA_CROP) != null) { 317 // TODO: Handle MtpImagew 318 Uri uri = dm.getContentUri(item.getPath()); 319 Intent intent = new Intent(CropImage.ACTION_CROP, uri) 320 .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT) 321 .putExtras(getData()); 322 if (mData.getParcelable(MediaStore.EXTRA_OUTPUT) == null) { 323 intent.putExtra(CropImage.KEY_RETURN_DATA, true); 324 } 325 activity.startActivity(intent); 326 activity.finish(); 327 } else { 328 Intent intent = new Intent(null, item.getContentUri()) 329 .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 330 activity.setResult(Activity.RESULT_OK, intent); 331 activity.finish(); 332 } 333 } 334 335 public void onLongTap(int slotIndex) { 336 if (mGetContent) return; 337 MediaItem item = mAlbumDataAdapter.get(slotIndex); 338 if (item == null) return; 339 mSelectionManager.setAutoLeaveSelectionMode(true); 340 mSelectionManager.toggle(item.getPath()); 341 mSlotView.invalidate(); 342 } 343 344 @Override 345 public void doCluster(int clusterType) { 346 String basePath = mMediaSet.getPath().toString(); 347 String newPath = FilterUtils.newClusterPath(basePath, clusterType); 348 Bundle data = new Bundle(getData()); 349 data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath); 350 if (mShowClusterMenu) { 351 Context context = mActivity.getAndroidContext(); 352 data.putString(AlbumSetPage.KEY_SET_TITLE, mMediaSet.getName()); 353 data.putString(AlbumSetPage.KEY_SET_SUBTITLE, 354 GalleryActionBar.getClusterByTypeString(context, clusterType)); 355 } 356 357 // mAlbumView.savePositions(PositionRepository.getInstance(mActivity)); 358 mActivity.getStateManager().startStateForResult( 359 AlbumSetPage.class, REQUEST_DO_ANIMATION, data); 360 } 361 362 @Override 363 protected void onCreate(Bundle data, Bundle restoreState) { 364 super.onCreate(data, restoreState); 365 mUserDistance = GalleryUtils.meterToPixel(USER_DISTANCE_METER); 366 initializeViews(); 367 initializeData(data); 368 mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false); 369 mShowClusterMenu = data.getBoolean(KEY_SHOW_CLUSTER_MENU, false); 370 mDetailsSource = new MyDetailsSource(); 371 Context context = mActivity.getAndroidContext(); 372 mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 373 374 // Enable auto-select-all for mtp album 375 if (data.getBoolean(KEY_AUTO_SELECT_ALL)) { 376 mSelectionManager.selectAll(); 377 } 378 379 mLaunchedFromPhotoPage = 380 mActivity.getStateManager().hasStateClass(PhotoPage.class); 381 mInCameraApp = data.getBoolean(PhotoPage.KEY_APP_BRIDGE, false); 382 383 mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { 384 @Override 385 public void handleMessage(Message message) { 386 switch (message.what) { 387 case MSG_PICK_PHOTO: { 388 pickPhoto(message.arg1); 389 break; 390 } 391 default: 392 throw new AssertionError(message.what); 393 } 394 } 395 }; 396 } 397 398 @Override 399 protected void onResume() { 400 super.onResume(); 401 mIsActive = true; 402 403 mResumeEffect = mActivity.getTransitionStore().get(KEY_RESUME_ANIMATION); 404 if (mResumeEffect != null) { 405 mAlbumView.setSlotFilter(mResumeEffect); 406 mResumeEffect.setPositionProvider(mPositionProvider); 407 mResumeEffect.start(); 408 } 409 410 setContentPane(mRootPane); 411 412 boolean enableHomeButton = (mActivity.getStateManager().getStateCount() > 1) | 413 mParentMediaSetString != null; 414 GalleryActionBar actionBar = mActivity.getGalleryActionBar(); 415 actionBar.setDisplayOptions(enableHomeButton, false); 416 if (!mGetContent) { 417 actionBar.enableAlbumModeMenu(GalleryActionBar.ALBUM_GRID_MODE_SELECTED, this); 418 } 419 420 // Set the reload bit here to prevent it exit this page in clearLoadingBit(). 421 setLoadingBit(BIT_LOADING_RELOAD); 422 mAlbumDataAdapter.resume(); 423 424 mAlbumView.resume(); 425 mAlbumView.setPressedIndex(-1); 426 mActionModeHandler.resume(); 427 if (!mInitialSynced) { 428 setLoadingBit(BIT_LOADING_SYNC); 429 mSyncTask = mMediaSet.requestSync(this); 430 } 431 mInCameraAndWantQuitOnPause = mInCameraApp; 432 } 433 434 @Override 435 protected void onPause() { 436 super.onPause(); 437 mIsActive = false; 438 439 if (mSelectionManager.inSelectionMode()) { 440 mSelectionManager.leaveSelectionMode(); 441 } 442 mAlbumView.setSlotFilter(null); 443 444 mAlbumDataAdapter.pause(); 445 mAlbumView.pause(); 446 DetailsHelper.pause(); 447 if (!mGetContent) { 448 mActivity.getGalleryActionBar().disableAlbumModeMenu(true); 449 } 450 451 if (mSyncTask != null) { 452 mSyncTask.cancel(); 453 mSyncTask = null; 454 clearLoadingBit(BIT_LOADING_SYNC); 455 } 456 mActionModeHandler.pause(); 457 458 // The camera app should always launch in capture mode when 459 // resumed, so make the next resume faster by closing the grid 460 // view now 461 if (mInCameraAndWantQuitOnPause) { 462 if (mActivity.getStateManager().getTopState() == this) 463 mActivity.getStateManager().finishState(this, false); 464 } 465 } 466 467 @Override 468 protected void onDestroy() { 469 super.onDestroy(); 470 if (mAlbumDataAdapter != null) { 471 mAlbumDataAdapter.setLoadingListener(null); 472 } 473 } 474 475 private void initializeViews() { 476 mSelectionManager = new SelectionManager(mActivity, false); 477 mSelectionManager.setSelectionListener(this); 478 Config.AlbumPage config = Config.AlbumPage.get(mActivity); 479 mSlotView = new SlotView(mActivity, config.slotViewSpec); 480 mAlbumView = new AlbumSlotRenderer(mActivity, mSlotView, 481 mSelectionManager, config.placeholderColor); 482 mSlotView.setSlotRenderer(mAlbumView); 483 mRootPane.addComponent(mSlotView); 484 mSlotView.setListener(new SlotView.SimpleListener() { 485 @Override 486 public void onDown(int index) { 487 AlbumPage.this.onDown(index); 488 } 489 490 @Override 491 public void onUp(boolean followedByLongPress) { 492 AlbumPage.this.onUp(followedByLongPress); 493 } 494 495 @Override 496 public void onSingleTapUp(int slotIndex) { 497 AlbumPage.this.onSingleTapUp(slotIndex); 498 } 499 500 @Override 501 public void onLongTap(int slotIndex) { 502 AlbumPage.this.onLongTap(slotIndex); 503 } 504 }); 505 mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager); 506 mActionModeHandler.setActionModeListener(new ActionModeListener() { 507 @Override 508 public boolean onActionItemClicked(MenuItem item) { 509 return onItemSelected(item); 510 } 511 }); 512 } 513 514 private void initializeData(Bundle data) { 515 mMediaSetPath = Path.fromString(data.getString(KEY_MEDIA_PATH)); 516 mParentMediaSetString = data.getString(KEY_PARENT_MEDIA_PATH); 517 mMediaSet = mActivity.getDataManager().getMediaSet(mMediaSetPath); 518 if (mMediaSet == null) { 519 Utils.fail("MediaSet is null. Path = %s", mMediaSetPath); 520 } 521 mSelectionManager.setSourceMediaSet(mMediaSet); 522 mAlbumDataAdapter = new AlbumDataLoader(mActivity, mMediaSet); 523 mAlbumDataAdapter.setLoadingListener(new MyLoadingListener()); 524 mAlbumView.setModel(mAlbumDataAdapter); 525 } 526 527 private void showDetails() { 528 mShowDetails = true; 529 if (mDetailsHelper == null) { 530 mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource); 531 mDetailsHelper.setCloseListener(new CloseListener() { 532 @Override 533 public void onClose() { 534 hideDetails(); 535 } 536 }); 537 } 538 mDetailsHelper.show(); 539 } 540 541 private void hideDetails() { 542 mShowDetails = false; 543 mDetailsHelper.hide(); 544 mAlbumView.setHighlightItemPath(null); 545 mSlotView.invalidate(); 546 } 547 548 @Override 549 protected boolean onCreateActionBar(Menu menu) { 550 GalleryActionBar actionBar = mActivity.getGalleryActionBar(); 551 MenuInflater inflator = getSupportMenuInflater(); 552 if (mGetContent) { 553 inflator.inflate(R.menu.pickup, menu); 554 int typeBits = mData.getInt(Gallery.KEY_TYPE_BITS, 555 DataManager.INCLUDE_IMAGE); 556 actionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits)); 557 } else { 558 inflator.inflate(R.menu.album, menu); 559 actionBar.setTitle(mMediaSet.getName()); 560 561 menu.findItem(R.id.action_slideshow) 562 .setVisible(!(mMediaSet instanceof MtpDevice)); 563 564 FilterUtils.setupMenuItems(actionBar, mMediaSetPath, true); 565 566 menu.findItem(R.id.action_group_by).setVisible(mShowClusterMenu); 567 menu.findItem(R.id.action_camera).setVisible( 568 MediaSetUtils.isCameraSource(mMediaSetPath) 569 && GalleryUtils.isCameraAvailable(mActivity)); 570 571 } 572 actionBar.setSubtitle(null); 573 return true; 574 } 575 576 private void prepareAnimationBackToFilmstrip(int slotIndex) { 577 if (mAlbumDataAdapter == null || !mAlbumDataAdapter.isActive(slotIndex)) return; 578 MediaItem item = mAlbumDataAdapter.get(slotIndex); 579 if (item == null) return; 580 TransitionStore transitions = mActivity.getTransitionStore(); 581 transitions.put(PhotoPage.KEY_INDEX_HINT, slotIndex); 582 transitions.put(PhotoPage.KEY_OPEN_ANIMATION_RECT, 583 mSlotView.getSlotRect(slotIndex, mRootPane)); 584 } 585 586 private void switchToFilmstrip() { 587 if (mAlbumDataAdapter.size() < 1) return; 588 int targetPhoto = mSlotView.getVisibleStart(); 589 prepareAnimationBackToFilmstrip(targetPhoto); 590 if(mLaunchedFromPhotoPage) { 591 onBackPressed(); 592 } else { 593 pickPhoto(targetPhoto, true); 594 } 595 } 596 597 @Override 598 protected boolean onItemSelected(MenuItem item) { 599 switch (item.getItemId()) { 600 case android.R.id.home: { 601 onUpPressed(); 602 return true; 603 } 604 case R.id.action_cancel: 605 mActivity.getStateManager().finishState(this); 606 return true; 607 case R.id.action_select: 608 mSelectionManager.setAutoLeaveSelectionMode(false); 609 mSelectionManager.enterSelectionMode(); 610 return true; 611 case R.id.action_group_by: { 612 mActivity.getGalleryActionBar().showClusterDialog(this); 613 return true; 614 } 615 case R.id.action_slideshow: { 616 mInCameraAndWantQuitOnPause = false; 617 Bundle data = new Bundle(); 618 data.putString(SlideshowPage.KEY_SET_PATH, 619 mMediaSetPath.toString()); 620 data.putBoolean(SlideshowPage.KEY_REPEAT, true); 621 mActivity.getStateManager().startStateForResult( 622 SlideshowPage.class, REQUEST_SLIDESHOW, data); 623 return true; 624 } 625 case R.id.action_details: { 626 if (mShowDetails) { 627 hideDetails(); 628 } else { 629 showDetails(); 630 } 631 return true; 632 } 633 case R.id.action_camera: { 634 GalleryUtils.startCameraActivity(mActivity); 635 return true; 636 } 637 default: 638 return false; 639 } 640 } 641 642 @Override 643 protected void onStateResult(int request, int result, Intent data) { 644 switch (request) { 645 case REQUEST_SLIDESHOW: { 646 // data could be null, if there is no images in the album 647 if (data == null) return; 648 mFocusIndex = data.getIntExtra(SlideshowPage.KEY_PHOTO_INDEX, 0); 649 mSlotView.setCenterIndex(mFocusIndex); 650 break; 651 } 652 case REQUEST_PHOTO: { 653 if (data == null) return; 654 mFocusIndex = data.getIntExtra(PhotoPage.KEY_RETURN_INDEX_HINT, 0); 655 mSlotView.makeSlotVisible(mFocusIndex); 656 break; 657 } 658 case REQUEST_DO_ANIMATION: { 659 mSlotView.startRisingAnimation(); 660 break; 661 } 662 } 663 } 664 665 @Override 666 public void onSelectionModeChange(int mode) { 667 switch (mode) { 668 case SelectionManager.ENTER_SELECTION_MODE: { 669 mActionModeHandler.startActionMode(); 670 if (mHapticsEnabled) mVibrator.vibrate(100); 671 break; 672 } 673 case SelectionManager.LEAVE_SELECTION_MODE: { 674 mActionModeHandler.finishActionMode(); 675 mRootPane.invalidate(); 676 break; 677 } 678 case SelectionManager.SELECT_ALL_MODE: { 679 mActionModeHandler.updateSupportedOperation(); 680 mRootPane.invalidate(); 681 break; 682 } 683 } 684 } 685 686 @Override 687 public void onSelectionChange(Path path, boolean selected) { 688 int count = mSelectionManager.getSelectedCount(); 689 String format = mActivity.getResources().getQuantityString( 690 R.plurals.number_of_items_selected, count); 691 mActionModeHandler.setTitle(String.format(format, count)); 692 mActionModeHandler.updateSupportedOperation(path, selected); 693 } 694 695 @Override 696 public void onSyncDone(final MediaSet mediaSet, final int resultCode) { 697 Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result=" 698 + resultCode); 699 ((Activity) mActivity).runOnUiThread(new Runnable() { 700 @Override 701 public void run() { 702 GLRoot root = mActivity.getGLRoot(); 703 root.lockRenderThread(); 704 try { 705 if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) { 706 mInitialSynced = true; 707 } 708 clearLoadingBit(BIT_LOADING_SYNC); 709 if (resultCode == MediaSet.SYNC_RESULT_ERROR && mIsActive 710 && (mAlbumDataAdapter.size() == 0)) { 711 // show error toast only if the album is empty 712 Toast.makeText(mActivity, R.string.sync_album_error, 713 Toast.LENGTH_LONG).show(); 714 } 715 } finally { 716 root.unlockRenderThread(); 717 } 718 } 719 }); 720 } 721 722 private void setLoadingBit(int loadTaskBit) { 723 mLoadingBits |= loadTaskBit; 724 } 725 726 private void clearLoadingBit(int loadTaskBit) { 727 mLoadingBits &= ~loadTaskBit; 728 if (mLoadingBits == 0 && mIsActive) { 729 if (mAlbumDataAdapter.size() == 0) { 730 Intent result = new Intent(); 731 result.putExtra(KEY_EMPTY_ALBUM, true); 732 setStateResult(Activity.RESULT_OK, result); 733 mActivity.getStateManager().finishState(this); 734 } 735 } 736 } 737 738 private class MyLoadingListener implements LoadingListener { 739 @Override 740 public void onLoadingStarted() { 741 setLoadingBit(BIT_LOADING_RELOAD); 742 } 743 744 @Override 745 public void onLoadingFinished() { 746 clearLoadingBit(BIT_LOADING_RELOAD); 747 } 748 } 749 750 private class MyDetailsSource implements DetailsHelper.DetailsSource { 751 private int mIndex; 752 753 @Override 754 public int size() { 755 return mAlbumDataAdapter.size(); 756 } 757 758 @Override 759 public int setIndex() { 760 Path id = mSelectionManager.getSelected(false).get(0); 761 mIndex = mAlbumDataAdapter.findItem(id); 762 return mIndex; 763 } 764 765 @Override 766 public MediaDetails getDetails() { 767 // this relies on setIndex() being called beforehand 768 MediaObject item = mAlbumDataAdapter.get(mIndex); 769 if (item != null) { 770 mAlbumView.setHighlightItemPath(item.getPath()); 771 return item.getDetails(); 772 } else { 773 return null; 774 } 775 } 776 } 777 778 @Override 779 public void onAlbumModeSelected(int mode) { 780 if (mode == GalleryActionBar.ALBUM_FILMSTRIP_MODE_SELECTED) { 781 switchToFilmstrip(); 782 } 783 } 784} 785