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