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