PhotoPage.java revision b1e9fd893d62adae1f92d29dfc08bc76f8764491
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.ActionBar.OnMenuVisibilityListener; 20import android.app.Activity; 21import android.content.ActivityNotFoundException; 22import android.content.Context; 23import android.content.Intent; 24import android.graphics.Rect; 25import android.net.Uri; 26import android.nfc.NfcAdapter; 27import android.os.Bundle; 28import android.os.Handler; 29import android.os.Message; 30import android.view.Menu; 31import android.view.MenuInflater; 32import android.view.MenuItem; 33import android.view.View; 34import android.view.WindowManager; 35import android.widget.ShareActionProvider; 36import android.widget.Toast; 37 38import com.android.gallery3d.R; 39import com.android.gallery3d.data.DataManager; 40import com.android.gallery3d.data.MediaDetails; 41import com.android.gallery3d.data.MediaItem; 42import com.android.gallery3d.data.MediaObject; 43import com.android.gallery3d.data.MediaSet; 44import com.android.gallery3d.data.MtpDevice; 45import com.android.gallery3d.data.Path; 46import com.android.gallery3d.data.SnailItem; 47import com.android.gallery3d.data.SnailSource; 48import com.android.gallery3d.picasasource.PicasaSource; 49import com.android.gallery3d.ui.DetailsHelper; 50import com.android.gallery3d.ui.DetailsHelper.CloseListener; 51import com.android.gallery3d.ui.DetailsHelper.DetailsSource; 52import com.android.gallery3d.ui.GLCanvas; 53import com.android.gallery3d.ui.GLView; 54import com.android.gallery3d.ui.ImportCompleteListener; 55import com.android.gallery3d.ui.MenuExecutor; 56import com.android.gallery3d.ui.PhotoView; 57import com.android.gallery3d.ui.ScreenNail; 58import com.android.gallery3d.ui.SelectionManager; 59import com.android.gallery3d.ui.SynchronizedHandler; 60import com.android.gallery3d.ui.UserInteractionListener; 61import com.android.gallery3d.util.GalleryUtils; 62 63public class PhotoPage extends ActivityState implements 64 PhotoView.Listener, UserInteractionListener, 65 OrientationManager.Listener, AppBridge.Server { 66 private static final String TAG = "PhotoPage"; 67 68 private static final int MSG_HIDE_BARS = 1; 69 private static final int MSG_LOCK_ORIENTATION = 2; 70 private static final int MSG_UNLOCK_ORIENTATION = 3; 71 private static final int MSG_ON_FULL_SCREEN_CHANGED = 4; 72 73 private static final int HIDE_BARS_TIMEOUT = 3500; 74 75 private static final int REQUEST_SLIDESHOW = 1; 76 private static final int REQUEST_CROP = 2; 77 private static final int REQUEST_CROP_PICASA = 3; 78 79 public static final String KEY_MEDIA_SET_PATH = "media-set-path"; 80 public static final String KEY_MEDIA_ITEM_PATH = "media-item-path"; 81 public static final String KEY_INDEX_HINT = "index-hint"; 82 public static final String KEY_OPEN_ANIMATION_RECT = "open-animation-rect"; 83 public static final String KEY_APP_BRIDGE = "app-bridge"; 84 85 public static final String KEY_RETURN_INDEX_HINT = "return-index-hint"; 86 87 private GalleryApp mApplication; 88 private SelectionManager mSelectionManager; 89 90 private PhotoView mPhotoView; 91 private PhotoPage.Model mModel; 92 private DetailsHelper mDetailsHelper; 93 private boolean mShowDetails; 94 private Path mPendingSharePath; 95 96 // mMediaSet could be null if there is no KEY_MEDIA_SET_PATH supplied. 97 // E.g., viewing a photo in gmail attachment 98 private MediaSet mMediaSet; 99 private Menu mMenu; 100 101 private int mCurrentIndex = 0; 102 private Handler mHandler; 103 private boolean mShowBars = true; 104 private GalleryActionBar mActionBar; 105 private MyMenuVisibilityListener mMenuVisibilityListener; 106 private boolean mIsMenuVisible; 107 private boolean mIsInteracting; 108 private MediaItem mCurrentPhoto = null; 109 private MenuExecutor mMenuExecutor; 110 private boolean mIsActive; 111 private ShareActionProvider mShareActionProvider; 112 private String mSetPathString; 113 // This is the original mSetPathString before adding the camera preview item. 114 private String mOriginalSetPathString; 115 private AppBridge mAppBridge; 116 private ScreenNail mScreenNail; 117 private MediaItem mScreenNailItem; 118 private OrientationManager mOrientationManager; 119 120 private NfcAdapter mNfcAdapter; 121 122 public static interface Model extends PhotoView.Model { 123 public void resume(); 124 public void pause(); 125 public boolean isEmpty(); 126 public MediaItem getCurrentMediaItem(); 127 public void setCurrentPhoto(Path path, int indexHint); 128 } 129 130 private class MyMenuVisibilityListener implements OnMenuVisibilityListener { 131 public void onMenuVisibilityChanged(boolean isVisible) { 132 mIsMenuVisible = isVisible; 133 refreshHidingMessage(); 134 } 135 } 136 137 private final GLView mRootPane = new GLView() { 138 139 @Override 140 protected void renderBackground(GLCanvas view) { 141 view.clearBuffer(); 142 } 143 144 @Override 145 protected void onLayout( 146 boolean changed, int left, int top, int right, int bottom) { 147 mPhotoView.layout(0, 0, right - left, bottom - top); 148 if (mShowDetails) { 149 mDetailsHelper.layout(left, mActionBar.getHeight(), right, bottom); 150 } 151 } 152 153 @Override 154 protected void orient(int displayRotation, int compensation) { 155 displayRotation = mOrientationManager.getDisplayRotation(); 156 Log.d(TAG, "orient -- display rotation " + displayRotation 157 + ", compensation = " + compensation); 158 super.orient(displayRotation, compensation); 159 } 160 }; 161 162 @Override 163 public void onCreate(Bundle data, Bundle restoreState) { 164 mActionBar = mActivity.getGalleryActionBar(); 165 mSelectionManager = new SelectionManager(mActivity, false); 166 mMenuExecutor = new MenuExecutor(mActivity, mSelectionManager); 167 168 mPhotoView = new PhotoView(mActivity); 169 mPhotoView.setListener(this); 170 mRootPane.addComponent(mPhotoView); 171 mApplication = (GalleryApp)((Activity) mActivity).getApplication(); 172 mOrientationManager = mActivity.getOrientationManager(); 173 mOrientationManager.addListener(this); 174 175 mSetPathString = data.getString(KEY_MEDIA_SET_PATH); 176 mOriginalSetPathString = mSetPathString; 177 mNfcAdapter = NfcAdapter.getDefaultAdapter(mActivity.getAndroidContext()); 178 Path itemPath = Path.fromString(data.getString(KEY_MEDIA_ITEM_PATH)); 179 180 if (mSetPathString != null) { 181 mAppBridge = (AppBridge) data.getParcelable(KEY_APP_BRIDGE); 182 if (mAppBridge != null) { 183 mOrientationManager.lockOrientation(); 184 185 // Get the ScreenNail from AppBridge and register it. 186 mScreenNail = mAppBridge.attachScreenNail(); 187 int id = SnailSource.registerScreenNail(mScreenNail); 188 Path screenNailSetPath = SnailSource.getSetPath(id); 189 Path screenNailItemPath = SnailSource.getItemPath(id); 190 mScreenNailItem = (MediaItem) mActivity.getDataManager() 191 .getMediaObject(screenNailItemPath); 192 193 // Combine the original MediaSet with the one for CameraScreenNail. 194 mSetPathString = "/combo/item/{" + screenNailSetPath + 195 "," + mSetPathString + "}"; 196 197 // Start from the screen nail. 198 itemPath = screenNailItemPath; 199 200 // Action bar should not be displayed when camera starts. 201 mFlags |= FLAG_HIDE_ACTION_BAR; 202 } 203 204 mMediaSet = mActivity.getDataManager().getMediaSet(mSetPathString); 205 mCurrentIndex = data.getInt(KEY_INDEX_HINT, 0); 206 if (mMediaSet == null) { 207 Log.w(TAG, "failed to restore " + mSetPathString); 208 } 209 PhotoDataAdapter pda = new PhotoDataAdapter( 210 mActivity, mPhotoView, mMediaSet, itemPath, mCurrentIndex, 211 mAppBridge == null ? -1 : 0); 212 mModel = pda; 213 mPhotoView.setModel(mModel); 214 215 pda.setDataListener(new PhotoDataAdapter.DataListener() { 216 217 @Override 218 public void onPhotoChanged(int index, Path item) { 219 mCurrentIndex = index; 220 if (item != null) { 221 MediaItem photo = mModel.getCurrentMediaItem(); 222 if (photo != null) updateCurrentPhoto(photo); 223 } 224 } 225 226 @Override 227 public void onLoadingFinished() { 228 GalleryUtils.setSpinnerVisibility((Activity) mActivity, false); 229 if (!mModel.isEmpty()) { 230 MediaItem photo = mModel.getCurrentMediaItem(); 231 if (photo != null) updateCurrentPhoto(photo); 232 } else if (mIsActive) { 233 mActivity.getStateManager().finishState(PhotoPage.this); 234 } 235 } 236 237 @Override 238 public void onLoadingStarted() { 239 GalleryUtils.setSpinnerVisibility((Activity) mActivity, true); 240 } 241 }); 242 } else { 243 // Get default media set by the URI 244 MediaItem mediaItem = (MediaItem) 245 mActivity.getDataManager().getMediaObject(itemPath); 246 mModel = new SinglePhotoDataAdapter(mActivity, mPhotoView, mediaItem); 247 mPhotoView.setModel(mModel); 248 updateCurrentPhoto(mediaItem); 249 } 250 251 mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { 252 @Override 253 public void handleMessage(Message message) { 254 switch (message.what) { 255 case MSG_HIDE_BARS: { 256 hideBars(); 257 break; 258 } 259 case MSG_LOCK_ORIENTATION: { 260 mOrientationManager.lockOrientation(); 261 break; 262 } 263 case MSG_UNLOCK_ORIENTATION: { 264 mOrientationManager.unlockOrientation(); 265 break; 266 } 267 case MSG_ON_FULL_SCREEN_CHANGED: { 268 mAppBridge.onFullScreenChanged(message.arg1 == 1); 269 break; 270 } 271 default: throw new AssertionError(message.what); 272 } 273 } 274 }; 275 276 // start the opening animation only if it's not restored. 277 if (restoreState == null) { 278 mPhotoView.setOpenAnimationRect((Rect) data.getParcelable(KEY_OPEN_ANIMATION_RECT)); 279 } 280 } 281 282 private void updateShareURI(Path path) { 283 if (mShareActionProvider != null) { 284 DataManager manager = mActivity.getDataManager(); 285 int type = manager.getMediaType(path); 286 Intent intent = new Intent(Intent.ACTION_SEND); 287 intent.setType(MenuExecutor.getMimeType(type)); 288 intent.putExtra(Intent.EXTRA_STREAM, manager.getContentUri(path)); 289 mShareActionProvider.setShareIntent(intent); 290 if (mNfcAdapter != null) { 291 mNfcAdapter.setBeamPushUris(new Uri[]{manager.getContentUri(path)}, 292 (Activity)mActivity); 293 } 294 mPendingSharePath = null; 295 } else { 296 // This happens when ActionBar is not created yet. 297 mPendingSharePath = path; 298 } 299 } 300 301 private void updateCurrentPhoto(MediaItem photo) { 302 if (mCurrentPhoto == photo) return; 303 mCurrentPhoto = photo; 304 if (mCurrentPhoto == null) return; 305 updateMenuOperations(); 306 // Hide the action bar when going back to camera preview. 307 if (photo == mScreenNailItem) hideBars(); 308 updateTitle(); 309 if (mShowDetails) { 310 mDetailsHelper.reloadDetails(mModel.getCurrentIndex()); 311 } 312 mPhotoView.showVideoPlayIcon( 313 photo.getMediaType() == MediaObject.MEDIA_TYPE_VIDEO); 314 315 if ((photo.getSupportedOperations() & MediaItem.SUPPORT_SHARE) != 0) { 316 updateShareURI(photo.getPath()); 317 } 318 } 319 320 private void updateTitle() { 321 if (mCurrentPhoto == null) return; 322 boolean showTitle = mActivity.getAndroidContext().getResources().getBoolean( 323 R.bool.show_action_bar_title); 324 if (showTitle && mCurrentPhoto.getName() != null) 325 mActionBar.setTitle(mCurrentPhoto.getName()); 326 else 327 mActionBar.setTitle(""); 328 } 329 330 private void updateMenuOperations() { 331 if (mMenu == null) return; 332 MenuItem item = mMenu.findItem(R.id.action_slideshow); 333 if (item != null) { 334 item.setVisible(canDoSlideShow()); 335 } 336 if (mCurrentPhoto == null) return; 337 int supportedOperations = mCurrentPhoto.getSupportedOperations(); 338 if (!GalleryUtils.isEditorAvailable((Context) mActivity, "image/*")) { 339 supportedOperations &= ~MediaObject.SUPPORT_EDIT; 340 } 341 342 MenuExecutor.updateMenuOperation(mMenu, supportedOperations); 343 } 344 345 private boolean canDoSlideShow() { 346 if (mMediaSet == null || mCurrentPhoto == null) { 347 return false; 348 } 349 if (mCurrentPhoto.getMediaType() != MediaObject.MEDIA_TYPE_IMAGE) { 350 return false; 351 } 352 if (mMediaSet instanceof MtpDevice) { 353 return false; 354 } 355 return true; 356 } 357 358 private void showBars() { 359 if (mShowBars) return; 360 mShowBars = true; 361 mActionBar.show(); 362 WindowManager.LayoutParams params = ((Activity) mActivity).getWindow().getAttributes(); 363 params.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; 364 ((Activity) mActivity).getWindow().setAttributes(params); 365 } 366 367 private void hideBars() { 368 if (!mShowBars) return; 369 mShowBars = false; 370 mActionBar.hide(); 371 WindowManager.LayoutParams params = ((Activity) mActivity).getWindow().getAttributes(); 372 params.systemUiVisibility = View. SYSTEM_UI_FLAG_LOW_PROFILE; 373 ((Activity) mActivity).getWindow().setAttributes(params); 374 } 375 376 private void refreshHidingMessage() { 377 mHandler.removeMessages(MSG_HIDE_BARS); 378 if (!mIsMenuVisible && !mIsInteracting) { 379 mHandler.sendEmptyMessageDelayed(MSG_HIDE_BARS, HIDE_BARS_TIMEOUT); 380 } 381 } 382 383 @Override 384 public void onUserInteraction() { 385 showBars(); 386 refreshHidingMessage(); 387 } 388 389 public void onUserInteractionTap() { 390 if (mShowBars) { 391 hideBars(); 392 mHandler.removeMessages(MSG_HIDE_BARS); 393 } else { 394 showBars(); 395 refreshHidingMessage(); 396 } 397 } 398 399 @Override 400 public void onUserInteractionBegin() { 401 showBars(); 402 mIsInteracting = true; 403 refreshHidingMessage(); 404 } 405 406 @Override 407 public void onUserInteractionEnd() { 408 mIsInteracting = false; 409 410 // This function could be called from GL thread (in SlotView.render) 411 // and post to the main thread. So, it could be executed while the 412 // activity is paused. 413 if (mIsActive) refreshHidingMessage(); 414 } 415 416 @Override 417 public void onOrientationCompensationChanged(int degrees) { 418 mActivity.getGLRoot().setOrientationCompensation(degrees); 419 } 420 421 @Override 422 protected void onBackPressed() { 423 if (mShowDetails) { 424 hideDetails(); 425 } else if (mScreenNail == null 426 || !switchWithCaptureAnimation(-1)) { 427 // We are leaving this page. Set the result now. 428 setResult(); 429 super.onBackPressed(); 430 } 431 } 432 433 private void onUpPressed() { 434 if (mActivity.getStateManager().getStateCount() > 1) { 435 super.onBackPressed(); 436 } else if (mOriginalSetPathString != null) { 437 // We're in view mode so set up the stacks on our own. 438 Bundle data = new Bundle(getData()); 439 data.putString(AlbumPage.KEY_MEDIA_PATH, mOriginalSetPathString); 440 data.putString(AlbumPage.KEY_PARENT_MEDIA_PATH, 441 mActivity.getDataManager().getTopSetPath( 442 DataManager.INCLUDE_ALL)); 443 mActivity.getStateManager().switchState(this, AlbumPage.class, data); 444 } 445 } 446 447 private void setResult() { 448 Intent result = null; 449 if (!mPhotoView.getFilmMode()) { 450 result = new Intent(); 451 result.putExtra(KEY_RETURN_INDEX_HINT, mCurrentIndex); 452 } 453 setStateResult(Activity.RESULT_OK, result); 454 } 455 456 ////////////////////////////////////////////////////////////////////////// 457 // AppBridge.Server interface 458 ////////////////////////////////////////////////////////////////////////// 459 460 @Override 461 public void setCameraNaturalFrame(Rect frame) { 462 mPhotoView.setCameraNaturalFrame(frame); 463 } 464 465 @Override 466 public boolean switchWithCaptureAnimation(int offset) { 467 return mPhotoView.switchWithCaptureAnimation(offset); 468 } 469 470 @Override 471 protected boolean onCreateActionBar(Menu menu) { 472 MenuInflater inflater = ((Activity) mActivity).getMenuInflater(); 473 inflater.inflate(R.menu.photo, menu); 474 mShareActionProvider = GalleryActionBar.initializeShareActionProvider(menu); 475 if (mPendingSharePath != null) updateShareURI(mPendingSharePath); 476 mMenu = menu; 477 mShowBars = true; 478 updateMenuOperations(); 479 updateTitle(); 480 return true; 481 } 482 483 @Override 484 protected boolean onItemSelected(MenuItem item) { 485 MediaItem current = mModel.getCurrentMediaItem(); 486 487 if (current == null) { 488 // item is not ready, ignore 489 return true; 490 } 491 492 int currentIndex = mModel.getCurrentIndex(); 493 Path path = current.getPath(); 494 495 DataManager manager = mActivity.getDataManager(); 496 int action = item.getItemId(); 497 boolean needsConfirm = false; 498 switch (action) { 499 case android.R.id.home: { 500 onUpPressed(); 501 return true; 502 } 503 case R.id.action_slideshow: { 504 Bundle data = new Bundle(); 505 data.putString(SlideshowPage.KEY_SET_PATH, mMediaSet.getPath().toString()); 506 data.putString(SlideshowPage.KEY_ITEM_PATH, path.toString()); 507 data.putInt(SlideshowPage.KEY_PHOTO_INDEX, currentIndex); 508 data.putBoolean(SlideshowPage.KEY_REPEAT, true); 509 mActivity.getStateManager().startStateForResult( 510 SlideshowPage.class, REQUEST_SLIDESHOW, data); 511 return true; 512 } 513 case R.id.action_crop: { 514 Activity activity = (Activity) mActivity; 515 Intent intent = new Intent(CropImage.CROP_ACTION); 516 intent.setClass(activity, CropImage.class); 517 intent.setData(manager.getContentUri(path)); 518 activity.startActivityForResult(intent, PicasaSource.isPicasaImage(current) 519 ? REQUEST_CROP_PICASA 520 : REQUEST_CROP); 521 return true; 522 } 523 case R.id.action_details: { 524 if (mShowDetails) { 525 hideDetails(); 526 } else { 527 showDetails(currentIndex); 528 } 529 return true; 530 } 531 case R.id.action_delete: 532 needsConfirm = true; 533 case R.id.action_setas: 534 case R.id.action_rotate_ccw: 535 case R.id.action_rotate_cw: 536 case R.id.action_show_on_map: 537 case R.id.action_edit: 538 mSelectionManager.deSelectAll(); 539 mSelectionManager.toggle(path); 540 mMenuExecutor.onMenuClicked(item, needsConfirm, null); 541 return true; 542 case R.id.action_import: 543 mSelectionManager.deSelectAll(); 544 mSelectionManager.toggle(path); 545 mMenuExecutor.onMenuClicked(item, needsConfirm, 546 new ImportCompleteListener(mActivity)); 547 return true; 548 default : 549 return false; 550 } 551 } 552 553 private void hideDetails() { 554 mShowDetails = false; 555 mDetailsHelper.hide(); 556 } 557 558 private void showDetails(int index) { 559 mShowDetails = true; 560 if (mDetailsHelper == null) { 561 mDetailsHelper = new DetailsHelper(mActivity, mRootPane, new MyDetailsSource()); 562 mDetailsHelper.setCloseListener(new CloseListener() { 563 public void onClose() { 564 hideDetails(); 565 } 566 }); 567 } 568 mDetailsHelper.reloadDetails(index); 569 mDetailsHelper.show(); 570 } 571 572 //////////////////////////////////////////////////////////////////////////// 573 // Callbacks from PhotoView 574 //////////////////////////////////////////////////////////////////////////// 575 @Override 576 public void onSingleTapUp(int x, int y) { 577 if (mAppBridge != null) { 578 if (mAppBridge.onSingleTapUp(x, y)) return; 579 } 580 581 MediaItem item = mModel.getCurrentMediaItem(); 582 if (item == null || item == mScreenNailItem) { 583 // item is not ready or it is camera preview, ignore 584 return; 585 } 586 587 boolean playVideo = 588 (item.getSupportedOperations() & MediaItem.SUPPORT_PLAY) != 0; 589 590 if (playVideo) { 591 // determine if the point is at center (1/6) of the photo view. 592 // (The position of the "play" icon is at center (1/6) of the photo) 593 int w = mPhotoView.getWidth(); 594 int h = mPhotoView.getHeight(); 595 playVideo = (Math.abs(x - w / 2) * 12 <= w) 596 && (Math.abs(y - h / 2) * 12 <= h); 597 } 598 599 if (playVideo) { 600 playVideo((Activity) mActivity, item.getPlayUri(), item.getName()); 601 } else { 602 onUserInteractionTap(); 603 } 604 } 605 606 @Override 607 public void lockOrientation() { 608 mHandler.sendEmptyMessage(MSG_LOCK_ORIENTATION); 609 } 610 611 @Override 612 public void unlockOrientation() { 613 // Temporarily disabled until Camera UI can switch orientation. 614 // mHandler.sendEmptyMessage(MSG_UNLOCK_ORIENTATION); 615 } 616 617 @Override 618 public void onFullScreenChanged(boolean full) { 619 Message m = mHandler.obtainMessage( 620 MSG_ON_FULL_SCREEN_CHANGED, full ? 1 : 0, 0); 621 m.sendToTarget(); 622 } 623 624 public static void playVideo(Activity activity, Uri uri, String title) { 625 try { 626 Intent intent = new Intent(Intent.ACTION_VIEW) 627 .setDataAndType(uri, "video/*"); 628 intent.putExtra(Intent.EXTRA_TITLE, title); 629 activity.startActivity(intent); 630 } catch (ActivityNotFoundException e) { 631 Toast.makeText(activity, activity.getString(R.string.video_err), 632 Toast.LENGTH_SHORT).show(); 633 } 634 } 635 636 @Override 637 protected void onStateResult(int requestCode, int resultCode, Intent data) { 638 switch (requestCode) { 639 case REQUEST_CROP: 640 if (resultCode == Activity.RESULT_OK) { 641 if (data == null) break; 642 Path path = mApplication.getDataManager() 643 .findPathByUri(data.getData(), data.getType()); 644 if (path != null) { 645 mModel.setCurrentPhoto(path, mCurrentIndex); 646 } 647 } 648 break; 649 case REQUEST_CROP_PICASA: { 650 Context context = mActivity.getAndroidContext(); 651 // TODO: Use crop_saved instead of photo_saved after its new translation is done. 652 String message = resultCode == Activity.RESULT_OK ? context.getString( 653 R.string.photo_saved, context.getString(R.string.folder_download)) 654 : context.getString(R.string.crop_not_saved); 655 Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 656 break; 657 } 658 case REQUEST_SLIDESHOW: { 659 if (data == null) break; 660 String path = data.getStringExtra(SlideshowPage.KEY_ITEM_PATH); 661 int index = data.getIntExtra(SlideshowPage.KEY_PHOTO_INDEX, 0); 662 if (path != null) { 663 mModel.setCurrentPhoto(Path.fromString(path), index); 664 } 665 } 666 } 667 } 668 669 @Override 670 public void onPause() { 671 super.onPause(); 672 mIsActive = false; 673 if (mAppBridge != null) mAppBridge.setServer(null); 674 DetailsHelper.pause(); 675 mPhotoView.pause(); 676 mModel.pause(); 677 mHandler.removeMessages(MSG_HIDE_BARS); 678 mActionBar.removeOnMenuVisibilityListener(mMenuVisibilityListener); 679 680 mMenuExecutor.pause(); 681 } 682 683 @Override 684 protected void onResume() { 685 super.onResume(); 686 mIsActive = true; 687 setContentPane(mRootPane); 688 689 mModel.resume(); 690 mPhotoView.resume(); 691 if (mMenuVisibilityListener == null) { 692 mMenuVisibilityListener = new MyMenuVisibilityListener(); 693 } 694 mActionBar.setDisplayOptions(mSetPathString != null, true); 695 mActionBar.addOnMenuVisibilityListener(mMenuVisibilityListener); 696 697 onUserInteraction(); 698 if (mAppBridge != null) { 699 mAppBridge.setServer(this); 700 mModel.moveTo(0); // move to the camera preview after resume 701 } 702 } 703 704 @Override 705 protected void onDestroy() { 706 if (mAppBridge != null) { 707 // Unregister the ScreenNail and notify mAppBridge. 708 SnailSource.unregisterScreenNail(mScreenNail); 709 mAppBridge.detachScreenNail(); 710 mAppBridge = null; 711 mScreenNail = null; 712 } 713 mOrientationManager.removeListener(this); 714 super.onDestroy(); 715 } 716 717 private class MyDetailsSource implements DetailsSource { 718 private int mIndex; 719 720 @Override 721 public MediaDetails getDetails() { 722 return mModel.getCurrentMediaItem().getDetails(); 723 } 724 725 @Override 726 public int size() { 727 return mMediaSet != null ? mMediaSet.getMediaItemCount() : 1; 728 } 729 730 @Override 731 public int findIndex(int indexHint) { 732 mIndex = indexHint; 733 return indexHint; 734 } 735 736 @Override 737 public int getIndex() { 738 return mIndex; 739 } 740 } 741} 742