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.os.Bundle; 24 import android.os.Handler; 25 import android.os.Message; 26 import android.view.HapticFeedbackConstants; 27 import android.view.Menu; 28 import android.view.MenuInflater; 29 import android.view.MenuItem; 30 import android.view.View; 31 import android.view.View.OnClickListener; 32 import android.widget.Button; 33 import android.widget.RelativeLayout; 34 import android.widget.Toast; 35 36 import com.android.gallery3d.R; 37 import com.android.gallery3d.common.Utils; 38 import com.android.gallery3d.data.DataManager; 39 import com.android.gallery3d.data.MediaDetails; 40 import com.android.gallery3d.data.MediaItem; 41 import com.android.gallery3d.data.MediaObject; 42 import com.android.gallery3d.data.MediaSet; 43 import com.android.gallery3d.data.Path; 44 import com.android.gallery3d.glrenderer.FadeTexture; 45 import com.android.gallery3d.glrenderer.GLCanvas; 46 import com.android.gallery3d.picasasource.PicasaSource; 47 import com.android.gallery3d.settings.GallerySettings; 48 import com.android.gallery3d.ui.ActionModeHandler; 49 import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener; 50 import com.android.gallery3d.ui.AlbumSetSlotRenderer; 51 import com.android.gallery3d.ui.DetailsHelper; 52 import com.android.gallery3d.ui.DetailsHelper.CloseListener; 53 import com.android.gallery3d.ui.GLRoot; 54 import com.android.gallery3d.ui.GLView; 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.HelpUtils; 61 62 import java.lang.ref.WeakReference; 63 import java.util.ArrayList; 64 65 public class AlbumSetPage extends ActivityState implements 66 SelectionManager.SelectionListener, GalleryActionBar.ClusterRunner, 67 EyePosition.EyePositionListener, MediaSet.SyncListener { 68 @SuppressWarnings("unused") 69 private static final String TAG = "AlbumSetPage"; 70 71 private static final int MSG_PICK_ALBUM = 1; 72 73 public static final String KEY_MEDIA_PATH = "media-path"; 74 public static final String KEY_SET_TITLE = "set-title"; 75 public static final String KEY_SET_SUBTITLE = "set-subtitle"; 76 public static final String KEY_SELECTED_CLUSTER_TYPE = "selected-cluster"; 77 78 private static final int DATA_CACHE_SIZE = 256; 79 private static final int REQUEST_DO_ANIMATION = 1; 80 81 private static final int BIT_LOADING_RELOAD = 1; 82 private static final int BIT_LOADING_SYNC = 2; 83 84 private boolean mIsActive = false; 85 private SlotView mSlotView; 86 private AlbumSetSlotRenderer mAlbumSetView; 87 private Config.AlbumSetPage mConfig; 88 89 private MediaSet mMediaSet; 90 private String mTitle; 91 private String mSubtitle; 92 private boolean mShowClusterMenu; 93 private GalleryActionBar mActionBar; 94 private int mSelectedAction; 95 96 protected SelectionManager mSelectionManager; 97 private AlbumSetDataLoader mAlbumSetDataAdapter; 98 99 private boolean mGetContent; 100 private boolean mGetAlbum; 101 private ActionModeHandler mActionModeHandler; 102 private DetailsHelper mDetailsHelper; 103 private MyDetailsSource mDetailsSource; 104 private boolean mShowDetails; 105 private EyePosition mEyePosition; 106 private Handler mHandler; 107 108 // The eyes' position of the user, the origin is at the center of the 109 // device and the unit is in pixels. 110 private float mX; 111 private float mY; 112 private float mZ; 113 114 private Future<Integer> mSyncTask = null; 115 116 private int mLoadingBits = 0; 117 private boolean mInitialSynced = false; 118 119 private Button mCameraButton; 120 private boolean mShowedEmptyToastForSelf = false; 121 122 @Override 123 protected int getBackgroundColorId() { 124 return R.color.albumset_background; 125 } 126 127 private final GLView mRootPane = new GLView() { 128 private final float mMatrix[] = new float[16]; 129 130 @Override 131 protected void onLayout( 132 boolean changed, int left, int top, int right, int bottom) { 133 mEyePosition.resetPosition(); 134 135 int slotViewTop = mActionBar.getHeight() + mConfig.paddingTop; 136 int slotViewBottom = bottom - top - mConfig.paddingBottom; 137 int slotViewRight = right - left; 138 139 if (mShowDetails) { 140 mDetailsHelper.layout(left, slotViewTop, right, bottom); 141 } else { 142 mAlbumSetView.setHighlightItemPath(null); 143 } 144 145 mSlotView.layout(0, slotViewTop, slotViewRight, slotViewBottom); 146 } 147 148 @Override 149 protected void render(GLCanvas canvas) { 150 canvas.save(GLCanvas.SAVE_FLAG_MATRIX); 151 GalleryUtils.setViewPointMatrix(mMatrix, 152 getWidth() / 2 + mX, getHeight() / 2 + mY, mZ); 153 canvas.multiplyMatrix(mMatrix, 0); 154 super.render(canvas); 155 canvas.restore(); 156 } 157 }; 158 159 @Override 160 public void onEyePositionChanged(float x, float y, float z) { 161 mRootPane.lockRendering(); 162 mX = x; 163 mY = y; 164 mZ = z; 165 mRootPane.unlockRendering(); 166 mRootPane.invalidate(); 167 } 168 169 @Override 170 public void onBackPressed() { 171 if (mShowDetails) { 172 hideDetails(); 173 } else if (mSelectionManager.inSelectionMode()) { 174 mSelectionManager.leaveSelectionMode(); 175 } else { 176 super.onBackPressed(); 177 } 178 } 179 180 private void getSlotCenter(int slotIndex, int center[]) { 181 Rect offset = new Rect(); 182 mRootPane.getBoundsOf(mSlotView, offset); 183 Rect r = mSlotView.getSlotRect(slotIndex); 184 int scrollX = mSlotView.getScrollX(); 185 int scrollY = mSlotView.getScrollY(); 186 center[0] = offset.left + (r.left + r.right) / 2 - scrollX; 187 center[1] = offset.top + (r.top + r.bottom) / 2 - scrollY; 188 } 189 190 public void onSingleTapUp(int slotIndex) { 191 if (!mIsActive) return; 192 193 if (mSelectionManager.inSelectionMode()) { 194 MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex); 195 if (targetSet == null) return; // Content is dirty, we shall reload soon 196 mSelectionManager.toggle(targetSet.getPath()); 197 mSlotView.invalidate(); 198 } else { 199 // Show pressed-up animation for the single-tap. 200 mAlbumSetView.setPressedIndex(slotIndex); 201 mAlbumSetView.setPressedUp(); 202 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_ALBUM, slotIndex, 0), 203 FadeTexture.DURATION); 204 } 205 } 206 207 private static boolean albumShouldOpenInFilmstrip(MediaSet album) { 208 int itemCount = album.getMediaItemCount(); 209 ArrayList<MediaItem> list = (itemCount == 1) ? album.getMediaItem(0, 1) : null; 210 // open in film strip only if there's one item in the album and the item exists 211 return (list != null && !list.isEmpty()); 212 } 213 214 WeakReference<Toast> mEmptyAlbumToast = null; 215 216 private void showEmptyAlbumToast(int toastLength) { 217 Toast toast; 218 if (mEmptyAlbumToast != null) { 219 toast = mEmptyAlbumToast.get(); 220 if (toast != null) { 221 toast.show(); 222 return; 223 } 224 } 225 toast = Toast.makeText(mActivity, R.string.empty_album, toastLength); 226 mEmptyAlbumToast = new WeakReference<Toast>(toast); 227 toast.show(); 228 } 229 230 private void hideEmptyAlbumToast() { 231 if (mEmptyAlbumToast != null) { 232 Toast toast = mEmptyAlbumToast.get(); 233 if (toast != null) toast.cancel(); 234 } 235 } 236 237 private void pickAlbum(int slotIndex) { 238 if (!mIsActive) return; 239 240 MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex); 241 if (targetSet == null) return; // Content is dirty, we shall reload soon 242 if (targetSet.getTotalMediaItemCount() == 0) { 243 showEmptyAlbumToast(Toast.LENGTH_SHORT); 244 return; 245 } 246 hideEmptyAlbumToast(); 247 248 String mediaPath = targetSet.getPath().toString(); 249 250 Bundle data = new Bundle(getData()); 251 int[] center = new int[2]; 252 getSlotCenter(slotIndex, center); 253 data.putIntArray(AlbumPage.KEY_SET_CENTER, center); 254 if (mGetAlbum && targetSet.isLeafAlbum()) { 255 Activity activity = mActivity; 256 Intent result = new Intent() 257 .putExtra(AlbumPicker.KEY_ALBUM_PATH, targetSet.getPath().toString()); 258 activity.setResult(Activity.RESULT_OK, result); 259 activity.finish(); 260 } else if (targetSet.getSubMediaSetCount() > 0) { 261 data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath); 262 mActivity.getStateManager().startStateForResult( 263 AlbumSetPage.class, REQUEST_DO_ANIMATION, data); 264 } else { 265 if (!mGetContent && albumShouldOpenInFilmstrip(targetSet)) { 266 data.putParcelable(PhotoPage.KEY_OPEN_ANIMATION_RECT, 267 mSlotView.getSlotRect(slotIndex, mRootPane)); 268 data.putInt(PhotoPage.KEY_INDEX_HINT, 0); 269 data.putString(PhotoPage.KEY_MEDIA_SET_PATH, 270 mediaPath); 271 data.putBoolean(PhotoPage.KEY_START_IN_FILMSTRIP, true); 272 data.putBoolean(PhotoPage.KEY_IN_CAMERA_ROLL, targetSet.isCameraRoll()); 273 mActivity.getStateManager().startStateForResult( 274 FilmstripPage.class, AlbumPage.REQUEST_PHOTO, data); 275 return; 276 } 277 data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath); 278 279 // We only show cluster menu in the first AlbumPage in stack 280 boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class); 281 data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum); 282 mActivity.getStateManager().startStateForResult( 283 AlbumPage.class, REQUEST_DO_ANIMATION, data); 284 } 285 } 286 287 private void onDown(int index) { 288 mAlbumSetView.setPressedIndex(index); 289 } 290 291 private void onUp(boolean followedByLongPress) { 292 if (followedByLongPress) { 293 // Avoid showing press-up animations for long-press. 294 mAlbumSetView.setPressedIndex(-1); 295 } else { 296 mAlbumSetView.setPressedUp(); 297 } 298 } 299 300 public void onLongTap(int slotIndex) { 301 if (mGetContent || mGetAlbum) return; 302 MediaSet set = mAlbumSetDataAdapter.getMediaSet(slotIndex); 303 if (set == null) return; 304 mSelectionManager.setAutoLeaveSelectionMode(true); 305 mSelectionManager.toggle(set.getPath()); 306 mSlotView.invalidate(); 307 } 308 309 @Override 310 public void doCluster(int clusterType) { 311 String basePath = mMediaSet.getPath().toString(); 312 String newPath = FilterUtils.switchClusterPath(basePath, clusterType); 313 Bundle data = new Bundle(getData()); 314 data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath); 315 data.putInt(KEY_SELECTED_CLUSTER_TYPE, clusterType); 316 mActivity.getStateManager().switchState(this, AlbumSetPage.class, data); 317 } 318 319 @Override 320 public void onCreate(Bundle data, Bundle restoreState) { 321 super.onCreate(data, restoreState); 322 initializeViews(); 323 initializeData(data); 324 Context context = mActivity.getAndroidContext(); 325 mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false); 326 mGetAlbum = data.getBoolean(Gallery.KEY_GET_ALBUM, false); 327 mTitle = data.getString(AlbumSetPage.KEY_SET_TITLE); 328 mSubtitle = data.getString(AlbumSetPage.KEY_SET_SUBTITLE); 329 mEyePosition = new EyePosition(context, this); 330 mDetailsSource = new MyDetailsSource(); 331 mActionBar = mActivity.getGalleryActionBar(); 332 mSelectedAction = data.getInt(AlbumSetPage.KEY_SELECTED_CLUSTER_TYPE, 333 FilterUtils.CLUSTER_BY_ALBUM); 334 335 mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { 336 @Override 337 public void handleMessage(Message message) { 338 switch (message.what) { 339 case MSG_PICK_ALBUM: { 340 pickAlbum(message.arg1); 341 break; 342 } 343 default: throw new AssertionError(message.what); 344 } 345 } 346 }; 347 } 348 349 @Override 350 public void onDestroy() { 351 super.onDestroy(); 352 cleanupCameraButton(); 353 mActionModeHandler.destroy(); 354 } 355 356 private boolean setupCameraButton() { 357 if (!GalleryUtils.isCameraAvailable(mActivity)) return false; 358 RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity) 359 .findViewById(R.id.gallery_root); 360 if (galleryRoot == null) return false; 361 362 mCameraButton = new Button(mActivity); 363 mCameraButton.setText(R.string.camera_label); 364 mCameraButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.frame_overlay_gallery_camera, 0, 0); 365 mCameraButton.setOnClickListener(new OnClickListener() { 366 @Override 367 public void onClick(View arg0) { 368 GalleryUtils.startCameraActivity(mActivity); 369 } 370 }); 371 RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams( 372 RelativeLayout.LayoutParams.WRAP_CONTENT, 373 RelativeLayout.LayoutParams.WRAP_CONTENT); 374 lp.addRule(RelativeLayout.CENTER_IN_PARENT); 375 galleryRoot.addView(mCameraButton, lp); 376 return true; 377 } 378 379 private void cleanupCameraButton() { 380 if (mCameraButton == null) return; 381 RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity) 382 .findViewById(R.id.gallery_root); 383 if (galleryRoot == null) return; 384 galleryRoot.removeView(mCameraButton); 385 mCameraButton = null; 386 } 387 388 private void showCameraButton() { 389 if (mCameraButton == null && !setupCameraButton()) return; 390 mCameraButton.setVisibility(View.VISIBLE); 391 } 392 393 private void hideCameraButton() { 394 if (mCameraButton == null) return; 395 mCameraButton.setVisibility(View.GONE); 396 } 397 398 private void clearLoadingBit(int loadingBit) { 399 mLoadingBits &= ~loadingBit; 400 if (mLoadingBits == 0 && mIsActive) { 401 if (mAlbumSetDataAdapter.size() == 0) { 402 // If this is not the top of the gallery folder hierarchy, 403 // tell the parent AlbumSetPage instance to handle displaying 404 // the empty album toast, otherwise show it within this 405 // instance 406 if (mActivity.getStateManager().getStateCount() > 1) { 407 Intent result = new Intent(); 408 result.putExtra(AlbumPage.KEY_EMPTY_ALBUM, true); 409 setStateResult(Activity.RESULT_OK, result); 410 mActivity.getStateManager().finishState(this); 411 } else { 412 mShowedEmptyToastForSelf = true; 413 showEmptyAlbumToast(Toast.LENGTH_LONG); 414 mSlotView.invalidate(); 415 showCameraButton(); 416 } 417 return; 418 } 419 } 420 // Hide the empty album toast if we are in the root instance of 421 // AlbumSetPage and the album is no longer empty (for instance, 422 // after a sync is completed and web albums have been synced) 423 if (mShowedEmptyToastForSelf) { 424 mShowedEmptyToastForSelf = false; 425 hideEmptyAlbumToast(); 426 hideCameraButton(); 427 } 428 } 429 430 private void setLoadingBit(int loadingBit) { 431 mLoadingBits |= loadingBit; 432 } 433 434 @Override 435 public void onPause() { 436 super.onPause(); 437 mIsActive = false; 438 mAlbumSetDataAdapter.pause(); 439 mAlbumSetView.pause(); 440 mActionModeHandler.pause(); 441 mEyePosition.pause(); 442 DetailsHelper.pause(); 443 // Call disableClusterMenu to avoid receiving callback after paused. 444 // Don't hide menu here otherwise the list menu will disappear earlier than 445 // the action bar, which is janky and unwanted behavior. 446 mActionBar.disableClusterMenu(false); 447 if (mSyncTask != null) { 448 mSyncTask.cancel(); 449 mSyncTask = null; 450 clearLoadingBit(BIT_LOADING_SYNC); 451 } 452 } 453 454 @Override 455 public void onResume() { 456 super.onResume(); 457 mIsActive = true; 458 setContentPane(mRootPane); 459 460 // Set the reload bit here to prevent it exit this page in clearLoadingBit(). 461 setLoadingBit(BIT_LOADING_RELOAD); 462 mAlbumSetDataAdapter.resume(); 463 464 mAlbumSetView.resume(); 465 mEyePosition.resume(); 466 mActionModeHandler.resume(); 467 if (mShowClusterMenu) { 468 mActionBar.enableClusterMenu(mSelectedAction, this); 469 } 470 if (!mInitialSynced) { 471 setLoadingBit(BIT_LOADING_SYNC); 472 mSyncTask = mMediaSet.requestSync(AlbumSetPage.this); 473 } 474 } 475 476 private void initializeData(Bundle data) { 477 String mediaPath = data.getString(AlbumSetPage.KEY_MEDIA_PATH); 478 mMediaSet = mActivity.getDataManager().getMediaSet(mediaPath); 479 mSelectionManager.setSourceMediaSet(mMediaSet); 480 mAlbumSetDataAdapter = new AlbumSetDataLoader( 481 mActivity, mMediaSet, DATA_CACHE_SIZE); 482 mAlbumSetDataAdapter.setLoadingListener(new MyLoadingListener()); 483 mAlbumSetView.setModel(mAlbumSetDataAdapter); 484 } 485 486 private void initializeViews() { 487 mSelectionManager = new SelectionManager(mActivity, true); 488 mSelectionManager.setSelectionListener(this); 489 490 mConfig = Config.AlbumSetPage.get(mActivity); 491 mSlotView = new SlotView(mActivity, mConfig.slotViewSpec); 492 mAlbumSetView = new AlbumSetSlotRenderer( 493 mActivity, mSelectionManager, mSlotView, mConfig.labelSpec, 494 mConfig.placeholderColor); 495 mSlotView.setSlotRenderer(mAlbumSetView); 496 mSlotView.setListener(new SlotView.SimpleListener() { 497 @Override 498 public void onDown(int index) { 499 AlbumSetPage.this.onDown(index); 500 } 501 502 @Override 503 public void onUp(boolean followedByLongPress) { 504 AlbumSetPage.this.onUp(followedByLongPress); 505 } 506 507 @Override 508 public void onSingleTapUp(int slotIndex) { 509 AlbumSetPage.this.onSingleTapUp(slotIndex); 510 } 511 512 @Override 513 public void onLongTap(int slotIndex) { 514 AlbumSetPage.this.onLongTap(slotIndex); 515 } 516 }); 517 518 mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager); 519 mActionModeHandler.setActionModeListener(new ActionModeListener() { 520 @Override 521 public boolean onActionItemClicked(MenuItem item) { 522 return onItemSelected(item); 523 } 524 }); 525 mRootPane.addComponent(mSlotView); 526 } 527 528 @Override 529 protected boolean onCreateActionBar(Menu menu) { 530 Activity activity = mActivity; 531 final boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class); 532 MenuInflater inflater = getSupportMenuInflater(); 533 534 if (mGetContent) { 535 inflater.inflate(R.menu.pickup, menu); 536 int typeBits = mData.getInt( 537 Gallery.KEY_TYPE_BITS, DataManager.INCLUDE_IMAGE); 538 mActionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits)); 539 } else if (mGetAlbum) { 540 inflater.inflate(R.menu.pickup, menu); 541 mActionBar.setTitle(R.string.select_album); 542 } else { 543 inflater.inflate(R.menu.albumset, menu); 544 boolean wasShowingClusterMenu = mShowClusterMenu; 545 mShowClusterMenu = !inAlbum; 546 boolean selectAlbums = !inAlbum && 547 mActionBar.getClusterTypeAction() == FilterUtils.CLUSTER_BY_ALBUM; 548 MenuItem selectItem = menu.findItem(R.id.action_select); 549 selectItem.setTitle(activity.getString( 550 selectAlbums ? R.string.select_album : R.string.select_group)); 551 552 MenuItem cameraItem = menu.findItem(R.id.action_camera); 553 cameraItem.setVisible(GalleryUtils.isCameraAvailable(activity)); 554 555 FilterUtils.setupMenuItems(mActionBar, mMediaSet.getPath(), false); 556 557 Intent helpIntent = HelpUtils.getHelpIntent(activity, R.string.help_url_gallery_main); 558 559 MenuItem helpItem = menu.findItem(R.id.action_general_help); 560 helpItem.setVisible(helpIntent != null); 561 if (helpIntent != null) helpItem.setIntent(helpIntent); 562 563 mActionBar.setTitle(mTitle); 564 mActionBar.setSubtitle(mSubtitle); 565 if (mShowClusterMenu != wasShowingClusterMenu) { 566 if (mShowClusterMenu) { 567 mActionBar.enableClusterMenu(mSelectedAction, this); 568 } else { 569 mActionBar.disableClusterMenu(true); 570 } 571 } 572 } 573 return true; 574 } 575 576 @Override 577 protected boolean onItemSelected(MenuItem item) { 578 Activity activity = mActivity; 579 switch (item.getItemId()) { 580 case R.id.action_cancel: 581 activity.setResult(Activity.RESULT_CANCELED); 582 activity.finish(); 583 return true; 584 case R.id.action_select: 585 mSelectionManager.setAutoLeaveSelectionMode(false); 586 mSelectionManager.enterSelectionMode(); 587 return true; 588 case R.id.action_details: 589 if (mAlbumSetDataAdapter.size() != 0) { 590 if (mShowDetails) { 591 hideDetails(); 592 } else { 593 showDetails(); 594 } 595 } else { 596 Toast.makeText(activity, 597 activity.getText(R.string.no_albums_alert), 598 Toast.LENGTH_SHORT).show(); 599 } 600 return true; 601 case R.id.action_camera: { 602 GalleryUtils.startCameraActivity(activity); 603 return true; 604 } 605 case R.id.action_manage_offline: { 606 Bundle data = new Bundle(); 607 String mediaPath = mActivity.getDataManager().getTopSetPath( 608 DataManager.INCLUDE_ALL); 609 data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath); 610 mActivity.getStateManager().startState(ManageCachePage.class, data); 611 return true; 612 } 613 case R.id.action_sync_picasa_albums: { 614 PicasaSource.requestSync(activity); 615 return true; 616 } 617 case R.id.action_settings: { 618 activity.startActivity(new Intent(activity, GallerySettings.class)); 619 return true; 620 } 621 default: 622 return false; 623 } 624 } 625 626 @Override 627 protected void onStateResult(int requestCode, int resultCode, Intent data) { 628 if (data != null && data.getBooleanExtra(AlbumPage.KEY_EMPTY_ALBUM, false)) { 629 showEmptyAlbumToast(Toast.LENGTH_SHORT); 630 } 631 switch (requestCode) { 632 case REQUEST_DO_ANIMATION: { 633 mSlotView.startRisingAnimation(); 634 } 635 } 636 } 637 638 private String getSelectedString() { 639 int count = mSelectionManager.getSelectedCount(); 640 int action = mActionBar.getClusterTypeAction(); 641 int string = action == FilterUtils.CLUSTER_BY_ALBUM 642 ? R.plurals.number_of_albums_selected 643 : R.plurals.number_of_groups_selected; 644 String format = mActivity.getResources().getQuantityString(string, count); 645 return String.format(format, count); 646 } 647 648 @Override 649 public void onSelectionModeChange(int mode) { 650 switch (mode) { 651 case SelectionManager.ENTER_SELECTION_MODE: { 652 mActionBar.disableClusterMenu(true); 653 mActionModeHandler.startActionMode(); 654 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 655 break; 656 } 657 case SelectionManager.LEAVE_SELECTION_MODE: { 658 mActionModeHandler.finishActionMode(); 659 if (mShowClusterMenu) { 660 mActionBar.enableClusterMenu(mSelectedAction, this); 661 } 662 mRootPane.invalidate(); 663 break; 664 } 665 case SelectionManager.SELECT_ALL_MODE: { 666 mActionModeHandler.updateSupportedOperation(); 667 mRootPane.invalidate(); 668 break; 669 } 670 } 671 } 672 673 @Override 674 public void onSelectionChange(Path path, boolean selected) { 675 mActionModeHandler.setTitle(getSelectedString()); 676 mActionModeHandler.updateSupportedOperation(path, selected); 677 } 678 679 private void hideDetails() { 680 mShowDetails = false; 681 mDetailsHelper.hide(); 682 mAlbumSetView.setHighlightItemPath(null); 683 mSlotView.invalidate(); 684 } 685 686 private void showDetails() { 687 mShowDetails = true; 688 if (mDetailsHelper == null) { 689 mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource); 690 mDetailsHelper.setCloseListener(new CloseListener() { 691 @Override 692 public void onClose() { 693 hideDetails(); 694 } 695 }); 696 } 697 mDetailsHelper.show(); 698 } 699 700 @Override 701 public void onSyncDone(final MediaSet mediaSet, final int resultCode) { 702 if (resultCode == MediaSet.SYNC_RESULT_ERROR) { 703 Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result=" 704 + resultCode); 705 } 706 ((Activity) mActivity).runOnUiThread(new Runnable() { 707 @Override 708 public void run() { 709 GLRoot root = mActivity.getGLRoot(); 710 root.lockRenderThread(); 711 try { 712 if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) { 713 mInitialSynced = true; 714 } 715 clearLoadingBit(BIT_LOADING_SYNC); 716 if (resultCode == MediaSet.SYNC_RESULT_ERROR && mIsActive) { 717 Log.w(TAG, "failed to load album set"); 718 } 719 } finally { 720 root.unlockRenderThread(); 721 } 722 } 723 }); 724 } 725 726 private class MyLoadingListener implements LoadingListener { 727 @Override 728 public void onLoadingStarted() { 729 setLoadingBit(BIT_LOADING_RELOAD); 730 } 731 732 @Override 733 public void onLoadingFinished(boolean loadingFailed) { 734 clearLoadingBit(BIT_LOADING_RELOAD); 735 } 736 } 737 738 private class MyDetailsSource implements DetailsHelper.DetailsSource { 739 private int mIndex; 740 741 @Override 742 public int size() { 743 return mAlbumSetDataAdapter.size(); 744 } 745 746 @Override 747 public int setIndex() { 748 Path id = mSelectionManager.getSelected(false).get(0); 749 mIndex = mAlbumSetDataAdapter.findSet(id); 750 return mIndex; 751 } 752 753 @Override 754 public MediaDetails getDetails() { 755 MediaObject item = mAlbumSetDataAdapter.getMediaSet(mIndex); 756 if (item != null) { 757 mAlbumSetView.setHighlightItemPath(item.getPath()); 758 return item.getDetails(); 759 } else { 760 return null; 761 } 762 } 763 } 764 } 765