CameraAppUI.java revision 8793eff1b85bda89047316fed36cdc1161a8b811
1/* 2 * Copyright (C) 2013 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.camera.app; 18 19import android.app.Activity; 20import android.content.Context; 21import android.graphics.Matrix; 22import android.graphics.SurfaceTexture; 23import android.hardware.display.DisplayManager; 24import android.util.Log; 25import android.view.GestureDetector; 26import android.view.LayoutInflater; 27import android.view.MotionEvent; 28import android.view.TextureView; 29import android.view.View; 30import android.view.ViewConfiguration; 31import android.view.ViewGroup; 32import android.widget.FrameLayout; 33 34import com.android.camera.AnimationManager; 35import com.android.camera.ShutterButton; 36import com.android.camera.TextureViewHelper; 37import com.android.camera.filmstrip.FilmstripContentPanel; 38import com.android.camera.ui.BottomBar; 39import com.android.camera.ui.CaptureAnimationOverlay; 40import com.android.camera.ui.MainActivityLayout; 41import com.android.camera.ui.ModeListView; 42import com.android.camera.ui.ModeTransitionView; 43import com.android.camera.ui.PreviewOverlay; 44import com.android.camera.ui.PreviewStatusListener; 45import com.android.camera.util.ApiHelper; 46import com.android.camera.util.CameraUtil; 47import com.android.camera.widget.FilmstripLayout; 48import com.android.camera.widget.IndicatorIconController; 49import com.android.camera.widget.IndicatorOverlay; 50import com.android.camera2.R; 51 52/** 53 * CameraAppUI centralizes control of views shared across modules. Whereas module 54 * specific views will be handled in each Module UI. For example, we can now 55 * bring the flash animation and capture animation up from each module to app 56 * level, as these animations are largely the same for all modules. 57 * 58 * This class also serves to disambiguate touch events. It recognizes all the 59 * swipe gestures that happen on the preview by attaching a touch listener to 60 * a full-screen view on top of preview TextureView. Since CameraAppUI has knowledge 61 * of how swipe from each direction should be handled, it can then redirect these 62 * events to appropriate recipient views. 63 */ 64public class CameraAppUI implements ModeListView.ModeSwitchListener, 65 TextureView.SurfaceTextureListener, ModeListView.ModeListOpenListener { 66 67 /** 68 * The bottom controls on the filmstrip. 69 */ 70 public static interface BottomControls { 71 /** Values for the view state of the button. */ 72 public final int VIEW_NONE = 0; 73 public final int VIEW_PHOTO_SPHERE = 1; 74 public final int VIEW_RGBZ = 2; 75 76 /** 77 * Sets a new or replaces an existing listener for bottom control events. 78 */ 79 void setListener(Listener listener); 80 81 /** 82 * Set if the bottom controls are visible. 83 * @param visible {@code true} if visible. 84 */ 85 void setVisible(boolean visible); 86 87 /** 88 * @param visible Whether the button is visible. 89 */ 90 void setEditButtonVisibility(boolean visible); 91 92 /** 93 * @param enabled Whether the button is enabled. 94 */ 95 void setEditEnabled(boolean enabled); 96 97 /** 98 * Sets the visibility of the view-photosphere button. 99 * 100 * @param state one of {@link #VIEW_NONE}, {@link #VIEW_PHOTO_SPHERE}, 101 * {@link #VIEW_RGBZ}. 102 */ 103 void setViewButtonVisibility(int state); 104 105 /** 106 * @param enabled Whether the button is enabled. 107 */ 108 void setViewEnabled(boolean enabled); 109 110 /** 111 * @param visible Whether the button is visible. 112 */ 113 void setTinyPlanetButtonVisibility(boolean visible); 114 115 /** 116 * @param enabled Whether the button is enabled. 117 */ 118 void setTinyPlanetEnabled(boolean enabled); 119 120 /** 121 * @param visible Whether the button is visible. 122 */ 123 void setDeleteButtonVisibility(boolean visible); 124 125 /** 126 * @param enabled Whether the button is enabled. 127 */ 128 void setDeleteEnabled(boolean enabled); 129 130 /** 131 * @param visible Whether the button is visible. 132 */ 133 void setShareButtonVisibility(boolean visible); 134 135 /** 136 * @param enabled Whether the button is enabled. 137 */ 138 void setShareEnabled(boolean enabled); 139 140 /** 141 * Classes implementing this interface can listen for events on the bottom 142 * controls. 143 */ 144 public static interface Listener { 145 /** 146 * Called when the user pressed the "view" button to e.g. view a photo 147 * sphere or RGBZ image. 148 */ 149 public void onExternalViewer(); 150 151 /** 152 * Called when the "edit" button is pressed. 153 */ 154 public void onEdit(); 155 156 /** 157 * Called when the "tiny planet" button is pressed. 158 */ 159 public void onTinyPlanet(); 160 161 /** 162 * Called when the "delete" button is pressed. 163 */ 164 public void onDelete(); 165 166 /** 167 * Called when the "share" button is pressed. 168 */ 169 public void onShare(); 170 } 171 } 172 173 private final static String TAG = "CameraAppUI"; 174 175 private final AppController mController; 176 private final boolean mIsCaptureIntent; 177 private final AnimationManager mAnimationManager; 178 179 // Swipe states: 180 private final static int IDLE = 0; 181 private final static int SWIPE_UP = 1; 182 private final static int SWIPE_DOWN = 2; 183 private final static int SWIPE_LEFT = 3; 184 private final static int SWIPE_RIGHT = 4; 185 private boolean mSwipeEnabled = true; 186 187 // Touch related measures: 188 private final int mSlop; 189 private final static int SWIPE_TIME_OUT_MS = 500; 190 191 private final static int SHIMMY_DELAY_MS = 1000; 192 193 // Mode cover states: 194 private final static int COVER_HIDDEN = 0; 195 private final static int COVER_SHOWN = 1; 196 private final static int COVER_WILL_HIDE_AT_NEXT_FRAME = 2; 197 private static final int COVER_WILL_HIDE_AT_NEXT_TEXTURE_UPDATE = 3; 198 199 // Bottom bar capture icons 200 public static final int CAMERA_SHUTTER_ICON = 0; 201 public static final int VIDEO_SHUTTER_ICON = 1; 202 public static final int STOP_SHUTTER_ICON = 2; 203 204 // App level views: 205 private final FrameLayout mCameraRootView; 206 private final ModeTransitionView mModeTransitionView; 207 private final MainActivityLayout mAppRootView; 208 private final ModeListView mModeListView; 209 private final FilmstripLayout mFilmstripLayout; 210 private TextureView mTextureView; 211 private FrameLayout mModuleUI; 212 private BottomBar mBottomBar; 213 private IndicatorOverlay mIndicatorOverlay; 214 private boolean mShouldShowShimmy = false; 215 private IndicatorIconController mIndicatorIconController; 216 217 private TextureViewHelper mTextureViewHelper; 218 private final GestureDetector mGestureDetector; 219 private DisplayManager.DisplayListener mDisplayListener; 220 private int mLastRotation; 221 private int mSwipeState = IDLE; 222 private PreviewOverlay mPreviewOverlay; 223 private CaptureAnimationOverlay mCaptureOverlay; 224 private PreviewStatusListener mPreviewStatusListener; 225 private int mModeCoverState = COVER_HIDDEN; 226 private final FilmstripBottomControls mFilmstripBottomControls; 227 private final FilmstripContentPanel mFilmstripPanel; 228 private Runnable mHideCoverRunnable; 229 private final View.OnLayoutChangeListener mPreviewLayoutChangeListener 230 = new View.OnLayoutChangeListener() { 231 @Override 232 public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, 233 int oldTop, int oldRight, int oldBottom) { 234 if (mPreviewStatusListener != null) { 235 mPreviewStatusListener.onPreviewLayoutChanged(v, left, top, right, bottom, oldLeft, 236 oldTop, oldRight, oldBottom); 237 } 238 } 239 }; 240 241 public void updatePreviewAspectRatio(float aspectRatio) { 242 mTextureViewHelper.updateAspectRatio(aspectRatio); 243 } 244 245 /** 246 * This is to support modules that calculate their own transform matrix because 247 * they need to use a transform matrix to rotate the preview. 248 * 249 * @param matrix transform matrix to be set on the TextureView 250 */ 251 public void updatePreviewTransform(Matrix matrix) { 252 mTextureViewHelper.updateTransform(matrix); 253 } 254 255 public interface AnimationFinishedListener { 256 public void onAnimationFinished(boolean success); 257 } 258 259 private class MyTouchListener implements View.OnTouchListener { 260 private boolean mScaleStarted = false; 261 @Override 262 public boolean onTouch(View v, MotionEvent event) { 263 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 264 mScaleStarted = false; 265 } else if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { 266 mScaleStarted = true; 267 } 268 return (!mScaleStarted) && mGestureDetector.onTouchEvent(event); 269 } 270 } 271 272 /** 273 * This gesture listener finds out the direction of the scroll gestures and 274 * sends them to CameraAppUI to do further handling. 275 */ 276 private class MyGestureListener extends GestureDetector.SimpleOnGestureListener { 277 private MotionEvent mDown; 278 279 @Override 280 public boolean onScroll(MotionEvent e1, MotionEvent ev, float distanceX, float distanceY) { 281 if (ev.getEventTime() - ev.getDownTime() > SWIPE_TIME_OUT_MS 282 || mSwipeState != IDLE 283 || mIsCaptureIntent 284 || !mSwipeEnabled) { 285 return false; 286 } 287 288 int deltaX = (int) (ev.getX() - mDown.getX()); 289 int deltaY = (int) (ev.getY() - mDown.getY()); 290 if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) { 291 if (Math.abs(deltaX) > mSlop || Math.abs(deltaY) > mSlop) { 292 // Calculate the direction of the swipe. 293 if (deltaX >= Math.abs(deltaY)) { 294 // Swipe right. 295 setSwipeState(SWIPE_RIGHT); 296 } else if (deltaX <= -Math.abs(deltaY)) { 297 // Swipe left. 298 setSwipeState(SWIPE_LEFT); 299 } else if (deltaY >= Math.abs(deltaX)) { 300 // Swipe down. 301 setSwipeState(SWIPE_DOWN); 302 } else if (deltaY <= -Math.abs(deltaX)) { 303 // Swipe up. 304 setSwipeState(SWIPE_UP); 305 } 306 } 307 } 308 return true; 309 } 310 311 private void setSwipeState(int swipeState) { 312 mSwipeState = swipeState; 313 // Notify new swipe detected. 314 onSwipeDetected(swipeState); 315 } 316 317 @Override 318 public boolean onDown(MotionEvent ev) { 319 mDown = MotionEvent.obtain(ev); 320 mSwipeState = IDLE; 321 return false; 322 } 323 } 324 325 public CameraAppUI(AppController controller, MainActivityLayout appRootView, 326 boolean isCaptureIntent) { 327 mSlop = ViewConfiguration.get(controller.getAndroidContext()).getScaledTouchSlop(); 328 mController = controller; 329 mIsCaptureIntent = isCaptureIntent; 330 331 mAppRootView = appRootView; 332 mFilmstripLayout = (FilmstripLayout) appRootView.findViewById(R.id.filmstrip_layout); 333 mCameraRootView = (FrameLayout) appRootView.findViewById(R.id.camera_app_root); 334 mModeTransitionView = (ModeTransitionView) 335 mAppRootView.findViewById(R.id.mode_transition_view); 336 mFilmstripBottomControls = new FilmstripBottomControls( 337 (ViewGroup) mAppRootView.findViewById(R.id.filmstrip_bottom_controls)); 338 mFilmstripPanel = (FilmstripContentPanel) mAppRootView.findViewById(R.id.filmstrip_layout); 339 mGestureDetector = new GestureDetector(controller.getAndroidContext(), 340 new MyGestureListener()); 341 mModeListView = (ModeListView) appRootView.findViewById(R.id.mode_list_layout); 342 if (mModeListView != null) { 343 mModeListView.setModeSwitchListener(this); 344 mModeListView.setModeListOpenListener(this); 345 } else { 346 Log.e(TAG, "Cannot find mode list in the view hierarchy"); 347 } 348 mAnimationManager = new AnimationManager(); 349 initDisplayListener(); 350 } 351 352 /** 353 * Enable or disable swipe gestures. We want to disable them e.g. while we 354 * record a video. 355 */ 356 public void setSwipeEnabled(boolean enabled) { 357 mAppRootView.setSwipeEnabled(enabled); 358 mSwipeEnabled = enabled; 359 } 360 361 /** 362 * Initializes the display listener to listen to display changes such as 363 * 180-degree rotation change, which will not have an onConfigurationChanged 364 * callback. 365 */ 366 private void initDisplayListener() { 367 if (ApiHelper.HAS_DISPLAY_LISTENER) { 368 mLastRotation = CameraUtil.getDisplayRotation( 369 (Activity) mController.getAndroidContext()); 370 371 mDisplayListener = new DisplayManager.DisplayListener() { 372 @Override 373 public void onDisplayAdded(int arg0) { 374 // Do nothing. 375 } 376 377 @Override 378 public void onDisplayChanged(int displayId) { 379 int rotation = CameraUtil.getDisplayRotation( 380 (Activity) mController.getAndroidContext()); 381 if ((rotation - mLastRotation + 360) % 360 == 180) { 382 mPreviewStatusListener.onPreviewFlipped(); 383 } 384 mLastRotation = rotation; 385 } 386 387 @Override 388 public void onDisplayRemoved(int arg0) { 389 // Do nothing. 390 } 391 }; 392 393 ((DisplayManager) mController.getAndroidContext() 394 .getSystemService(Context.DISPLAY_SERVICE)) 395 .registerDisplayListener(mDisplayListener, null); 396 } 397 } 398 399 /** 400 * Redirects touch events to appropriate recipient views based on swipe direction. 401 * More specifically, swipe up and swipe down will be handled by the view that handles 402 * mode transition; swipe left will be send to filmstrip; swipe right will be redirected 403 * to mode list in order to bring up mode list. 404 */ 405 private void onSwipeDetected(int swipeState) { 406 if (swipeState == SWIPE_UP || swipeState == SWIPE_DOWN) { 407 // Quick switch between modes. 408 int currentModuleIndex = mController.getCurrentModuleIndex(); 409 final int moduleToTransitionTo = 410 mController.getQuickSwitchToModuleId(currentModuleIndex); 411 if (currentModuleIndex != moduleToTransitionTo) { 412 mAppRootView.redirectTouchEventsTo(mModeTransitionView); 413 414 int shadeColorId = CameraUtil.getCameraThemeColorId(moduleToTransitionTo, 415 mController.getAndroidContext()); 416 int iconRes = CameraUtil.getCameraModeIconResId(moduleToTransitionTo, 417 mController.getAndroidContext()); 418 419 AnimationFinishedListener listener = new AnimationFinishedListener() { 420 @Override 421 public void onAnimationFinished(boolean success) { 422 if (success) { 423 mHideCoverRunnable = new Runnable() { 424 @Override 425 public void run() { 426 mModeTransitionView.startPeepHoleAnimation(); 427 } 428 }; 429 mModeCoverState = COVER_SHOWN; 430 // Go to new module when the previous operation is successful. 431 mController.onModeSelected(moduleToTransitionTo); 432 } 433 } 434 }; 435 if (mSwipeState == SWIPE_UP) { 436 mModeTransitionView.prepareToPullUpShade(shadeColorId, iconRes, listener); 437 } else { 438 mModeTransitionView.prepareToPullDownShade(shadeColorId, iconRes, listener); 439 } 440 } 441 } else if (swipeState == SWIPE_LEFT) { 442 // Pass the touch sequence to filmstrip layout. 443 mAppRootView.redirectTouchEventsTo(mFilmstripLayout); 444 } else if (swipeState == SWIPE_RIGHT) { 445 // Pass the touch to mode switcher 446 mAppRootView.redirectTouchEventsTo(mModeListView); 447 } 448 } 449 450 /** 451 * Gets called when activity resumes in preview. 452 */ 453 public void resume() { 454 if (mTextureView == null || mTextureView.getSurfaceTexture() != null) { 455 if (!mIsCaptureIntent) { 456 showShimmyDelayed(); 457 } 458 } else { 459 // Show mode theme cover until preview is ready 460 showModeCoverUntilPreviewReady(); 461 } 462 // Hide action bar first since we are in full screen mode first, and 463 // switch the system UI to lights-out mode. 464 mFilmstripPanel.hide(); 465 } 466 467 /** 468 * A cover view showing the mode theme color and mode icon will be visible on 469 * top of preview until preview is ready (i.e. camera preview is started and 470 * the first frame has been received). 471 */ 472 private void showModeCoverUntilPreviewReady() { 473 int modeId = mController.getCurrentModuleIndex(); 474 int colorId = CameraUtil.getCameraThemeColorId(modeId, mController.getAndroidContext()); 475 int iconId = CameraUtil.getCameraModeIconResId(modeId, mController.getAndroidContext()); 476 mModeTransitionView.setupModeCover(colorId, iconId); 477 mHideCoverRunnable = new Runnable() { 478 @Override 479 public void run() { 480 mModeTransitionView.hideModeCover(new AnimationFinishedListener() { 481 @Override 482 public void onAnimationFinished(boolean success) { 483 if (success) { 484 showShimmyDelayed(); 485 } 486 } 487 }); 488 } 489 }; 490 mModeCoverState = COVER_SHOWN; 491 } 492 493 private void showShimmyDelayed() { 494 if (!mIsCaptureIntent) { 495 // Show shimmy in SHIMMY_DELAY_MS 496 mShouldShowShimmy = mController.shouldShowShimmy(); 497 if (mShouldShowShimmy) { 498 mModeListView.startAccordionAnimationWithDelay(SHIMMY_DELAY_MS); 499 } 500 } 501 } 502 503 private void hideModeCover() { 504 if (mHideCoverRunnable != null) { 505 mAppRootView.post(mHideCoverRunnable); 506 mHideCoverRunnable = null; 507 } 508 mModeCoverState = COVER_HIDDEN; 509 } 510 511 @Override 512 public void onOpenFullScreen() { 513 if (mShouldShowShimmy) { 514 mController.decrementShimmyPlayTimes(); 515 // Sets should show shimmy flag to false for this session (i.e. until 516 // next onResume) 517 mShouldShowShimmy = false; 518 } 519 } 520 521 /** 522 * Called when the back key is pressed. 523 * 524 * @return Whether the UI responded to the key event. 525 */ 526 public boolean onBackPressed() { 527 if (mFilmstripLayout.getVisibility() == View.VISIBLE) { 528 return mFilmstripLayout.onBackPressed(); 529 } else { 530 return mModeListView.onBackPressed(); 531 } 532 } 533 534 /** 535 * Sets a {@link com.android.camera.ui.PreviewStatusListener} that 536 * listens to SurfaceTexture changes. In addition, listeners are set on 537 * dependent app ui elements. 538 * 539 * @param previewStatusListener the listener that gets notified when SurfaceTexture 540 * changes 541 */ 542 public void setPreviewStatusListener(PreviewStatusListener previewStatusListener) { 543 mPreviewStatusListener = previewStatusListener; 544 if (mPreviewStatusListener != null) { 545 onPreviewListenerChanged(); 546 } 547 } 548 549 /** 550 * When the PreviewStatusListener changes, listeners need to be 551 * set on the following app ui elements: 552 * {@link com.android.camera.ui.PreviewOverlay}, 553 * {@link com.android.camera.ui.BottomBar}, 554 * {@link com.android.camera.ui.IndicatorOverlay}, 555 * {@link com.android.camera.ui.IndicatorIconController}. 556 */ 557 private void onPreviewListenerChanged() { 558 // Set a listener for recognizing preview gestures. 559 GestureDetector.OnGestureListener gestureListener 560 = mPreviewStatusListener.getGestureListener(); 561 if (gestureListener != null) { 562 mPreviewOverlay.setGestureListener(gestureListener); 563 } 564 565 // Set a listener for resizing the bottom bar on 566 // preview size changes. 567 mTextureViewHelper.setAutoAdjustTransform( 568 mPreviewStatusListener.shouldAutoAdjustTransformMatrixOnLayout()); 569 if (mPreviewStatusListener.shouldAutoAdjustBottomBar()) { 570 mBottomBar = (BottomBar) mCameraRootView.findViewById(R.id.bottom_bar); 571 mTextureViewHelper.addPreviewAreaSizeChangedListener(mBottomBar); 572 } 573 574 // Set a listener for resizing the indicator overlay on 575 // preview size changes. 576 mIndicatorOverlay = (IndicatorOverlay) mAppRootView.findViewById( 577 R.id.indicator_overlay); 578 mTextureViewHelper.addPreviewAreaSizeChangedListener(mIndicatorOverlay); 579 580 if (mIndicatorIconController == null) { 581 mIndicatorIconController = 582 new IndicatorIconController(mController, mAppRootView); 583 } 584 mController.getSettingsManager().addListener(mIndicatorIconController); 585 } 586 587 /** 588 * This method should be called in onCameraOpened. It defines CameraAppUI 589 * specific changes that depend on the camera or camera settings. 590 */ 591 public void onChangeCamera() { 592 if (mIndicatorIconController != null) { 593 // Sync the settings state with the indicator state. 594 mIndicatorIconController.syncIndicators(); 595 } 596 } 597 598 /** 599 * Adds a listener to receive callbacks when preview area size changes. 600 */ 601 public void addPreviewAreaSizeChangedListener( 602 PreviewStatusListener.PreviewAreaSizeChangedListener listener) { 603 mTextureViewHelper.addPreviewAreaSizeChangedListener(listener); 604 } 605 606 /** 607 * Removes a listener that receives callbacks when preview area size changes. 608 */ 609 public void removePreviewAreaSizeChangedListener( 610 PreviewStatusListener.PreviewAreaSizeChangedListener listener) { 611 mTextureViewHelper.removePreviewAreaSizeChangedListener(listener); 612 } 613 614 /** 615 * This inflates generic_module layout, which contains all the shared views across 616 * modules. Then each module inflates their own views in the given view group. For 617 * now, this is called every time switching from a not-yet-refactored module to a 618 * refactored module. In the future, this should only need to be done once per app 619 * start. 620 */ 621 public void prepareModuleUI() { 622 mCameraRootView.removeAllViews(); 623 LayoutInflater inflater = (LayoutInflater) mController.getAndroidContext() 624 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 625 inflater.inflate(R.layout.generic_module, mCameraRootView, true); 626 627 mModuleUI = (FrameLayout) mCameraRootView.findViewById(R.id.module_layout); 628 mTextureView = (TextureView) mCameraRootView.findViewById(R.id.preview_content); 629 mTextureViewHelper = new TextureViewHelper(mTextureView); 630 mTextureViewHelper.setSurfaceTextureListener(this); 631 mTextureViewHelper.setOnLayoutChangeListener(mPreviewLayoutChangeListener); 632 633 mBottomBar = (BottomBar) mCameraRootView.findViewById(R.id.bottom_bar); 634 mBottomBar.setupToggle(mIsCaptureIntent); 635 636 mPreviewOverlay = (PreviewOverlay) mCameraRootView.findViewById(R.id.preview_overlay); 637 mPreviewOverlay.setOnTouchListener(new MyTouchListener()); 638 mPreviewOverlay.setOnPreviewTouchedListener(mBottomBar); 639 640 mCaptureOverlay = (CaptureAnimationOverlay) 641 mCameraRootView.findViewById(R.id.capture_overlay); 642 mTextureViewHelper.addPreviewAreaSizeChangedListener(mPreviewOverlay); 643 mTextureViewHelper.addPreviewAreaSizeChangedListener(mCaptureOverlay); 644 645 if (mIndicatorIconController == null) { 646 mIndicatorIconController = 647 new IndicatorIconController(mController, mAppRootView); 648 } 649 650 mController.getButtonManager().load(mCameraRootView); 651 mController.getButtonManager().setListener(mIndicatorIconController); 652 } 653 654 // TODO: Remove this when refactor is done. 655 // This is here to ensure refactored modules can work with not-yet-refactored ones. 656 public void clearCameraUI() { 657 mCameraRootView.removeAllViews(); 658 mModuleUI = null; 659 mTextureView = null; 660 mPreviewOverlay = null; 661 mBottomBar = null; 662 mIndicatorOverlay = null; 663 mIndicatorIconController = null; 664 setBottomBarShutterListener(null); 665 } 666 667 /** 668 * Called indirectly from each module in their initialization to get a view group 669 * to inflate the module specific views in. 670 * 671 * @return a view group for modules to attach views to 672 */ 673 public FrameLayout getModuleRootView() { 674 // TODO: Change it to mModuleUI when refactor is done 675 return mCameraRootView; 676 } 677 678 /** 679 * Remove all the module specific views. 680 */ 681 public void clearModuleUI() { 682 if (mModuleUI != null) { 683 mModuleUI.removeAllViews(); 684 } 685 mTextureViewHelper.addPreviewAreaSizeChangedListener(null); 686 687 mPreviewStatusListener = null; 688 mPreviewOverlay.reset(); 689 } 690 691 /** 692 * Gets called when preview is started. 693 */ 694 public void onPreviewStarted() { 695 if (mModeCoverState == COVER_SHOWN) { 696 mModeCoverState = COVER_WILL_HIDE_AT_NEXT_TEXTURE_UPDATE; 697 } 698 } 699 700 /** 701 * Gets notified when next preview frame comes in. 702 */ 703 public void onNewPreviewFrame() { 704 hideModeCover(); 705 mModeCoverState = COVER_HIDDEN; 706 } 707 708 /** 709 * Gets called when a mode is selected from {@link com.android.camera.ui.ModeListView} 710 * 711 * @param modeIndex mode index of the selected mode 712 */ 713 @Override 714 public void onModeSelected(int modeIndex) { 715 mHideCoverRunnable = new Runnable() { 716 @Override 717 public void run() { 718 mModeListView.startModeSelectionAnimation(); 719 } 720 }; 721 mModeCoverState = COVER_SHOWN; 722 723 int lastIndex = mController.getCurrentModuleIndex(); 724 mController.onModeSelected(modeIndex); 725 int currentIndex = mController.getCurrentModuleIndex(); 726 727 if (mTextureView == null) { 728 // TODO: Remove this when all the modules use TextureView 729 int temporaryDelay = 600; // ms 730 mModeListView.postDelayed(new Runnable() { 731 @Override 732 public void run() { 733 hideModeCover(); 734 } 735 }, temporaryDelay); 736 } else if (lastIndex == currentIndex) { 737 hideModeCover(); 738 } 739 } 740 741 /********************** Capture animation **********************/ 742 /* TODO: This session is subject to UX changes. In addition to the generic 743 flash animation and post capture animation, consider designating a parameter 744 for specifying the type of animation, as well as an animation finished listener 745 so that modules can have more knowledge of the status of the animation. */ 746 747 /** 748 * Starts the pre-capture animation. 749 */ 750 public void startPreCaptureAnimation() { 751 mCaptureOverlay.startFlashAnimation(); 752 } 753 754 /** 755 * Cancels the pre-capture animation. 756 */ 757 public void cancelPreCaptureAnimation() { 758 mAnimationManager.cancelAnimations(); 759 } 760 761 /** 762 * Cancels the post-capture animation. 763 */ 764 public void cancelPostCaptureAnimation() { 765 mAnimationManager.cancelAnimations(); 766 } 767 768 public FilmstripContentPanel getFilmstripContentPanel() { 769 return mFilmstripPanel; 770 } 771 772 /** 773 * @return The {@link com.android.camera.app.CameraAppUI.BottomControls} on the 774 * bottom of the filmstrip. 775 */ 776 public BottomControls getFilmstripBottomControls() { 777 return mFilmstripBottomControls; 778 } 779 780 /** 781 * @param listener The listener for bottom controls. 782 */ 783 public void setFilmstripBottomControlsListener(BottomControls.Listener listener) { 784 mFilmstripBottomControls.setListener(listener); 785 } 786 787 /***************************SurfaceTexture Listener*********************************/ 788 789 @Override 790 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 791 Log.v(TAG, "SurfaceTexture is available"); 792 if (mPreviewStatusListener != null) { 793 mPreviewStatusListener.onSurfaceTextureAvailable(surface, width, height); 794 } 795 } 796 797 @Override 798 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 799 if (mPreviewStatusListener != null) { 800 mPreviewStatusListener.onSurfaceTextureSizeChanged(surface, width, height); 801 } 802 } 803 804 @Override 805 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 806 Log.v(TAG, "SurfaceTexture is destroyed"); 807 if (mPreviewStatusListener != null) { 808 return mPreviewStatusListener.onSurfaceTextureDestroyed(surface); 809 } 810 return false; 811 } 812 813 @Override 814 public void onSurfaceTextureUpdated(SurfaceTexture surface) { 815 if (mModeCoverState == COVER_WILL_HIDE_AT_NEXT_TEXTURE_UPDATE) { 816 hideModeCover(); 817 mModeCoverState = COVER_HIDDEN; 818 } 819 if (mPreviewStatusListener != null) { 820 mPreviewStatusListener.onSurfaceTextureUpdated(surface); 821 } 822 } 823 824 /** 825 * Sets the color of the bottom bar. 826 */ 827 public void setBottomBarColor(int colorId) { 828 mBottomBar.setBackgroundColor(colorId); 829 } 830 831 /** 832 * Sets the pressed color of the bottom bar. 833 */ 834 public void setBottomBarPressedColor(int colorId) { 835 mBottomBar.setBackgroundPressedColor(colorId); 836 } 837 838 /** 839 * converts a icon enum to a resource id 840 */ 841 private int shutterIconId(int w) { 842 int resId = 0; 843 switch(w) { 844 case VIDEO_SHUTTER_ICON: 845 resId = R.drawable.ic_video_normal; 846 break; 847 case STOP_SHUTTER_ICON: 848 resId = R.drawable.ic_stop_normal; 849 break; 850 case CAMERA_SHUTTER_ICON: 851 default: 852 resId = R.drawable.ic_camera_normal; 853 } 854 return resId; 855 } 856 857 /** 858 * Sets the shutter button icon on the bottom bar 859 */ 860 public void setBottomBarShutterIcon(int w) { 861 mBottomBar.setShutterButtonIcon(shutterIconId(w)); 862 } 863 864 public void animateBottomBarToCircle(int w) { 865 mBottomBar.animateToCircle(shutterIconId(w)); 866 } 867 868 public void animateBottomBarToFullSize(int w) { 869 mBottomBar.animateToFullSize(shutterIconId(w)); 870 } 871 872 /** 873 * Set the visibility of the bottom bar. 874 */ 875 // TODO: needed for when panorama is managed by the generic module ui. 876 public void setBottomBarVisible(boolean visible) { 877 mBottomBar.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); 878 } 879 880 /** 881 * If the bottom bar is visible (hence has been drawn), 882 * this sets a {@link #ShutterButton.OnShutterButtonListener} 883 * on the global shutter button, 884 */ 885 public void setBottomBarShutterListener( 886 ShutterButton.OnShutterButtonListener listener) { 887 ShutterButton shutterButton 888 = (ShutterButton) mCameraRootView.findViewById(R.id.shutter_button); 889 if (shutterButton != null) { 890 shutterButton.setOnShutterButtonListener(listener); 891 } 892 } 893 894 /** 895 * Performs a transition to the global intent layout. 896 */ 897 public void transitionToIntentLayout() { 898 mBottomBar.transitionToIntentLayout(); 899 } 900 901 /** 902 * Performs a transition to the global intent review layout. 903 */ 904 public void transitionToIntentReviewLayout() { 905 mBottomBar.transitionToIntentReviewLayout(); 906 } 907} 908