AlbumPage.java revision 35e7b4ae727394aace466ebcf33d89adf01b690c
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 mAlbumView.setSlotFilter(null); 440 441 mAlbumDataAdapter.pause(); 442 mAlbumView.pause(); 443 DetailsHelper.pause(); 444 if (!mGetContent) { 445 mActivity.getGalleryActionBar().disableAlbumModeMenu(true); 446 } 447 448 if (mSyncTask != null) { 449 mSyncTask.cancel(); 450 mSyncTask = null; 451 clearLoadingBit(BIT_LOADING_SYNC); 452 } 453 mActionModeHandler.pause(); 454 455 // The camera app should always launch in capture mode when 456 // resumed, so make the next resume faster by closing the grid 457 // view now 458 if (mInCameraAndWantQuitOnPause) { 459 if (mActivity.getStateManager().getTopState() == this) 460 mActivity.getStateManager().finishState(this, false); 461 } 462 } 463 464 @Override 465 protected void onDestroy() { 466 super.onDestroy(); 467 if (mAlbumDataAdapter != null) { 468 mAlbumDataAdapter.setLoadingListener(null); 469 } 470 } 471 472 private void initializeViews() { 473 mSelectionManager = new SelectionManager(mActivity, false); 474 mSelectionManager.setSelectionListener(this); 475 Config.AlbumPage config = Config.AlbumPage.get(mActivity); 476 mSlotView = new SlotView(mActivity, config.slotViewSpec); 477 mAlbumView = new AlbumSlotRenderer(mActivity, mSlotView, 478 mSelectionManager, config.placeholderColor); 479 mSlotView.setSlotRenderer(mAlbumView); 480 mRootPane.addComponent(mSlotView); 481 mSlotView.setListener(new SlotView.SimpleListener() { 482 @Override 483 public void onDown(int index) { 484 AlbumPage.this.onDown(index); 485 } 486 487 @Override 488 public void onUp(boolean followedByLongPress) { 489 AlbumPage.this.onUp(followedByLongPress); 490 } 491 492 @Override 493 public void onSingleTapUp(int slotIndex) { 494 AlbumPage.this.onSingleTapUp(slotIndex); 495 } 496 497 @Override 498 public void onLongTap(int slotIndex) { 499 AlbumPage.this.onLongTap(slotIndex); 500 } 501 }); 502 mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager); 503 mActionModeHandler.setActionModeListener(new ActionModeListener() { 504 @Override 505 public boolean onActionItemClicked(MenuItem item) { 506 return onItemSelected(item); 507 } 508 }); 509 } 510 511 private void initializeData(Bundle data) { 512 mMediaSetPath = Path.fromString(data.getString(KEY_MEDIA_PATH)); 513 mParentMediaSetString = data.getString(KEY_PARENT_MEDIA_PATH); 514 mMediaSet = mActivity.getDataManager().getMediaSet(mMediaSetPath); 515 if (mMediaSet == null) { 516 Utils.fail("MediaSet is null. Path = %s", mMediaSetPath); 517 } 518 mSelectionManager.setSourceMediaSet(mMediaSet); 519 mAlbumDataAdapter = new AlbumDataLoader(mActivity, mMediaSet); 520 mAlbumDataAdapter.setLoadingListener(new MyLoadingListener()); 521 mAlbumView.setModel(mAlbumDataAdapter); 522 } 523 524 private void showDetails() { 525 mShowDetails = true; 526 if (mDetailsHelper == null) { 527 mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource); 528 mDetailsHelper.setCloseListener(new CloseListener() { 529 @Override 530 public void onClose() { 531 hideDetails(); 532 } 533 }); 534 } 535 mDetailsHelper.show(); 536 } 537 538 private void hideDetails() { 539 mShowDetails = false; 540 mDetailsHelper.hide(); 541 mAlbumView.setHighlightItemPath(null); 542 mSlotView.invalidate(); 543 } 544 545 @Override 546 protected boolean onCreateActionBar(Menu menu) { 547 GalleryActionBar actionBar = mActivity.getGalleryActionBar(); 548 MenuInflater inflator = getSupportMenuInflater(); 549 if (mGetContent) { 550 inflator.inflate(R.menu.pickup, menu); 551 int typeBits = mData.getInt(Gallery.KEY_TYPE_BITS, 552 DataManager.INCLUDE_IMAGE); 553 actionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits)); 554 } else { 555 inflator.inflate(R.menu.album, menu); 556 actionBar.setTitle(mMediaSet.getName()); 557 558 menu.findItem(R.id.action_slideshow) 559 .setVisible(!(mMediaSet instanceof MtpDevice)); 560 561 FilterUtils.setupMenuItems(actionBar, mMediaSetPath, true); 562 563 menu.findItem(R.id.action_group_by).setVisible(mShowClusterMenu); 564 menu.findItem(R.id.action_camera).setVisible( 565 MediaSetUtils.isCameraSource(mMediaSetPath) 566 && GalleryUtils.isCameraAvailable(mActivity)); 567 568 } 569 actionBar.setSubtitle(null); 570 return true; 571 } 572 573 private void prepareAnimationBackToFilmstrip(int slotIndex) { 574 if (mAlbumDataAdapter == null || !mAlbumDataAdapter.isActive(slotIndex)) return; 575 MediaItem item = mAlbumDataAdapter.get(slotIndex); 576 if (item == null) return; 577 TransitionStore transitions = mActivity.getTransitionStore(); 578 transitions.put(PhotoPage.KEY_INDEX_HINT, slotIndex); 579 transitions.put(PhotoPage.KEY_OPEN_ANIMATION_RECT, 580 mSlotView.getSlotRect(slotIndex, mRootPane)); 581 } 582 583 private void switchToFilmstrip() { 584 if (mAlbumDataAdapter.size() < 1) return; 585 int targetPhoto = mSlotView.getVisibleStart(); 586 prepareAnimationBackToFilmstrip(targetPhoto); 587 if(mLaunchedFromPhotoPage) { 588 onBackPressed(); 589 } else { 590 pickPhoto(targetPhoto, true); 591 } 592 } 593 594 @Override 595 protected boolean onItemSelected(MenuItem item) { 596 switch (item.getItemId()) { 597 case android.R.id.home: { 598 onUpPressed(); 599 return true; 600 } 601 case R.id.action_cancel: 602 mActivity.getStateManager().finishState(this); 603 return true; 604 case R.id.action_select: 605 mSelectionManager.setAutoLeaveSelectionMode(false); 606 mSelectionManager.enterSelectionMode(); 607 return true; 608 case R.id.action_group_by: { 609 mActivity.getGalleryActionBar().showClusterDialog(this); 610 return true; 611 } 612 case R.id.action_slideshow: { 613 mInCameraAndWantQuitOnPause = false; 614 Bundle data = new Bundle(); 615 data.putString(SlideshowPage.KEY_SET_PATH, 616 mMediaSetPath.toString()); 617 data.putBoolean(SlideshowPage.KEY_REPEAT, true); 618 mActivity.getStateManager().startStateForResult( 619 SlideshowPage.class, REQUEST_SLIDESHOW, data); 620 return true; 621 } 622 case R.id.action_details: { 623 if (mShowDetails) { 624 hideDetails(); 625 } else { 626 showDetails(); 627 } 628 return true; 629 } 630 case R.id.action_camera: { 631 GalleryUtils.startCameraActivity(mActivity); 632 return true; 633 } 634 default: 635 return false; 636 } 637 } 638 639 @Override 640 protected void onStateResult(int request, int result, Intent data) { 641 switch (request) { 642 case REQUEST_SLIDESHOW: { 643 // data could be null, if there is no images in the album 644 if (data == null) return; 645 mFocusIndex = data.getIntExtra(SlideshowPage.KEY_PHOTO_INDEX, 0); 646 mSlotView.setCenterIndex(mFocusIndex); 647 break; 648 } 649 case REQUEST_PHOTO: { 650 if (data == null) return; 651 mFocusIndex = data.getIntExtra(PhotoPage.KEY_RETURN_INDEX_HINT, 0); 652 mSlotView.makeSlotVisible(mFocusIndex); 653 break; 654 } 655 case REQUEST_DO_ANIMATION: { 656 mSlotView.startRisingAnimation(); 657 break; 658 } 659 } 660 } 661 662 @Override 663 public void onSelectionModeChange(int mode) { 664 switch (mode) { 665 case SelectionManager.ENTER_SELECTION_MODE: { 666 mActionModeHandler.startActionMode(); 667 if (mHapticsEnabled) mVibrator.vibrate(100); 668 break; 669 } 670 case SelectionManager.LEAVE_SELECTION_MODE: { 671 mActionModeHandler.finishActionMode(); 672 mRootPane.invalidate(); 673 break; 674 } 675 case SelectionManager.SELECT_ALL_MODE: { 676 mActionModeHandler.updateSupportedOperation(); 677 mRootPane.invalidate(); 678 break; 679 } 680 } 681 } 682 683 @Override 684 public void onSelectionChange(Path path, boolean selected) { 685 int count = mSelectionManager.getSelectedCount(); 686 String format = mActivity.getResources().getQuantityString( 687 R.plurals.number_of_items_selected, count); 688 mActionModeHandler.setTitle(String.format(format, count)); 689 mActionModeHandler.updateSupportedOperation(path, selected); 690 } 691 692 @Override 693 public void onSyncDone(final MediaSet mediaSet, final int resultCode) { 694 Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result=" 695 + resultCode); 696 ((Activity) mActivity).runOnUiThread(new Runnable() { 697 @Override 698 public void run() { 699 GLRoot root = mActivity.getGLRoot(); 700 root.lockRenderThread(); 701 try { 702 if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) { 703 mInitialSynced = true; 704 } 705 clearLoadingBit(BIT_LOADING_SYNC); 706 if (resultCode == MediaSet.SYNC_RESULT_ERROR && mIsActive 707 && (mAlbumDataAdapter.size() == 0)) { 708 // show error toast only if the album is empty 709 Toast.makeText(mActivity, R.string.sync_album_error, 710 Toast.LENGTH_LONG).show(); 711 } 712 } finally { 713 root.unlockRenderThread(); 714 } 715 } 716 }); 717 } 718 719 private void setLoadingBit(int loadTaskBit) { 720 mLoadingBits |= loadTaskBit; 721 } 722 723 private void clearLoadingBit(int loadTaskBit) { 724 mLoadingBits &= ~loadTaskBit; 725 if (mLoadingBits == 0 && mIsActive) { 726 if (mAlbumDataAdapter.size() == 0) { 727 Intent result = new Intent(); 728 result.putExtra(KEY_EMPTY_ALBUM, true); 729 setStateResult(Activity.RESULT_OK, result); 730 mActivity.getStateManager().finishState(this); 731 } 732 } 733 } 734 735 private class MyLoadingListener implements LoadingListener { 736 @Override 737 public void onLoadingStarted() { 738 setLoadingBit(BIT_LOADING_RELOAD); 739 } 740 741 @Override 742 public void onLoadingFinished() { 743 clearLoadingBit(BIT_LOADING_RELOAD); 744 } 745 } 746 747 private class MyDetailsSource implements DetailsHelper.DetailsSource { 748 private int mIndex; 749 750 @Override 751 public int size() { 752 return mAlbumDataAdapter.size(); 753 } 754 755 @Override 756 public int setIndex() { 757 Path id = mSelectionManager.getSelected(false).get(0); 758 mIndex = mAlbumDataAdapter.findItem(id); 759 return mIndex; 760 } 761 762 @Override 763 public MediaDetails getDetails() { 764 // this relies on setIndex() being called beforehand 765 MediaObject item = mAlbumDataAdapter.get(mIndex); 766 if (item != null) { 767 mAlbumView.setHighlightItemPath(item.getPath()); 768 return item.getDetails(); 769 } else { 770 return null; 771 } 772 } 773 } 774 775 @Override 776 public void onAlbumModeSelected(int mode) { 777 if (mode == GalleryActionBar.ALBUM_FILMSTRIP_MODE_SELECTED) { 778 switchToFilmstrip(); 779 } 780 } 781} 782