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