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