CameraAppUI.java revision 4a010db8a60008b2bf67b93b64f77f63affc29f3
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.content.Context; 20import android.graphics.Matrix; 21import android.graphics.RectF; 22import android.graphics.SurfaceTexture; 23import android.util.Log; 24import android.view.GestureDetector; 25import android.view.LayoutInflater; 26import android.view.MotionEvent; 27import android.view.TextureView; 28import android.view.View; 29import android.view.ViewConfiguration; 30import android.view.ViewGroup; 31import android.widget.FrameLayout; 32import android.widget.FrameLayout.LayoutParams; 33 34import com.android.camera.AnimationManager; 35import com.android.camera.filmstrip.FilmstripContentPanel; 36import com.android.camera.ui.BottomBar; 37import com.android.camera.ui.CaptureAnimationOverlay; 38import com.android.camera.ui.MainActivityLayout; 39import com.android.camera.ui.ModeListView; 40import com.android.camera.ui.ModeTransitionView; 41import com.android.camera.ui.PreviewOverlay; 42import com.android.camera.ui.PreviewStatusListener; 43import com.android.camera.widget.FilmstripLayout; 44import com.android.camera2.R; 45 46/** 47 * CameraAppUI centralizes control of views shared across modules. Whereas module 48 * specific views will be handled in each Module UI. For example, we can now 49 * bring the flash animation and capture animation up from each module to app 50 * level, as these animations are largely the same for all modules. 51 * 52 * This class also serves to disambiguate touch events. It recognizes all the 53 * swipe gestures that happen on the preview by attaching a touch listener to 54 * a full-screen view on top of preview TextureView. Since CameraAppUI has knowledge 55 * of how swipe from each direction should be handled, it can then redirect these 56 * events to appropriate recipient views. 57 */ 58public class CameraAppUI implements ModeListView.ModeSwitchListener, 59 TextureView.SurfaceTextureListener { 60 61 /** 62 * The bottom controls on the filmstrip. 63 */ 64 public static interface BottomControls { 65 /** Values for the view state of the button. */ 66 public final int VIEW_NONE = 0; 67 public final int VIEW_PHOTO_SPHERE = 1; 68 public final int VIEW_RGBZ = 2; 69 70 /** 71 * Sets a new or replaces an existing listener for bottom control events. 72 */ 73 void setListener(Listener listener); 74 75 /** 76 * Set if the bottom controls are visible. 77 * @param visible {@code true} if visible. 78 */ 79 void setVisible(boolean visible); 80 81 /** 82 * @param visible Whether the button is visible. 83 */ 84 void setEditButtonVisibility(boolean visible); 85 86 /** 87 * @param enabled Whether the button is enabled. 88 */ 89 void setEditEnabled(boolean enabled); 90 91 /** 92 * Sets the visibility of the view-photosphere button. 93 * 94 * @param state one of {@link #VIEW_NONE}, {@link #VIEW_PHOTO_SPHERE}, 95 * {@link #VIEW_RGBZ}. 96 */ 97 void setViewButtonVisibility(int state); 98 99 /** 100 * @param enabled Whether the button is enabled. 101 */ 102 void setViewEnabled(boolean enabled); 103 104 /** 105 * @param visible Whether the button is visible. 106 */ 107 void setTinyPlanetButtonVisibility(boolean visible); 108 109 /** 110 * @param enabled Whether the button is enabled. 111 */ 112 void setTinyPlanetEnabled(boolean enabled); 113 114 /** 115 * @param visible Whether the button is visible. 116 */ 117 void setDeleteButtonVisibility(boolean visible); 118 119 /** 120 * @param enabled Whether the button is enabled. 121 */ 122 void setDeleteEnabled(boolean enabled); 123 124 /** 125 * @param visible Whether the button is visible. 126 */ 127 void setShareButtonVisibility(boolean visible); 128 129 /** 130 * @param enabled Whether the button is enabled. 131 */ 132 void setShareEnabled(boolean enabled); 133 134 /** 135 * @param visible Whether the button is visible. 136 */ 137 void setGalleryButtonVisibility(boolean visible); 138 139 /** 140 * Classes implementing this interface can listen for events on the bottom 141 * controls. 142 */ 143 public static interface Listener { 144 /** 145 * Called when the user pressed the "view" button to e.g. view a photo 146 * sphere or RGBZ image. 147 */ 148 public void onView(); 149 150 /** 151 * Called when the "edit" button is pressed. 152 */ 153 public void onEdit(); 154 155 /** 156 * Called when the "tiny planet" button is pressed. 157 */ 158 public void onTinyPlanet(); 159 160 /** 161 * Called when the "delete" button is pressed. 162 */ 163 public void onDelete(); 164 165 /** 166 * Called when the "share" button is pressed. 167 */ 168 public void onShare(); 169 170 /** 171 * Called when the "gallery" button is pressed. 172 */ 173 public void onGallery(); 174 } 175 } 176 177 private final static String TAG = "CameraAppUI"; 178 179 private final AppController mController; 180 private final boolean mIsCaptureIntent; 181 private final boolean mIsSecureCamera; 182 private final AnimationManager mAnimationManager; 183 184 // Swipe states: 185 private final static int IDLE = 0; 186 private final static int SWIPE_UP = 1; 187 private final static int SWIPE_DOWN = 2; 188 private final static int SWIPE_LEFT = 3; 189 private final static int SWIPE_RIGHT = 4; 190 191 // Touch related measures: 192 private final int mSlop; 193 private final static int SWIPE_TIME_OUT_MS = 500; 194 195 private final static int SHIMMY_DELAY_MS = 1000; 196 197 // Mode cover states: 198 private final static int COVER_HIDDEN = 0; 199 private final static int COVER_SHOWN = 1; 200 private final static int COVER_WILL_HIDE_AT_NEXT_FRAME = 2; 201 202 // App level views: 203 private final FrameLayout mCameraRootView; 204 private final ModeTransitionView mModeTransitionView; 205 private final MainActivityLayout mAppRootView; 206 private final ModeListView mModeListView; 207 private final FilmstripLayout mFilmstripLayout; 208 private TextureView mTextureView; 209 private View mFlashOverlay; 210 private FrameLayout mModuleUI; 211 212 private final GestureDetector mGestureDetector; 213 private int mSwipeState = IDLE; 214 private PreviewOverlay mPreviewOverlay; 215 private CaptureAnimationOverlay mCaptureOverlay; 216 private PreviewStatusListener mPreviewStatusListener; 217 private int mModeCoverState = COVER_HIDDEN; 218 private final FilmstripBottomControls mFilmstripBottomControls; 219 private final FilmstripContentPanel mFilmstripPanel; 220 private Runnable mHideCoverRunnable; 221 private final View.OnLayoutChangeListener mPreviewLayoutChangeListener 222 = new View.OnLayoutChangeListener() { 223 @Override 224 public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, 225 int oldTop, int oldRight, int oldBottom) { 226 if (mPreviewStatusListener != null) { 227 mPreviewStatusListener.onPreviewLayoutChanged(v, left, top, right, bottom, oldLeft, 228 oldTop, oldRight, oldBottom); 229 } 230 } 231 }; 232 233 // TODO this isn't used by all modules universally, should be part of a util class or something 234 /** 235 * Resizes the preview texture and given bottom bar for 100% preview size 236 */ 237 public void adjustPreviewAndBottomBarSize(int width, int height, 238 BottomBar bottomBar, float aspectRatio, 239 int bottomBarMinHeight, int bottomBarOptimalHeight) { 240 Matrix matrix = mTextureView.getTransform(null); 241 242 float scaleX = 1f, scaleY = 1f; 243 float scaledTextureWidth, scaledTextureHeight; 244 if (width > height) { 245 scaledTextureWidth = Math.min(width, 246 (int) (height * aspectRatio)); 247 scaledTextureHeight = Math.min(height, 248 (int) (width / aspectRatio)); 249 } else { 250 scaledTextureWidth = Math.min(width, 251 (int) (height / aspectRatio)); 252 scaledTextureHeight = Math.min(height, 253 (int) (width * aspectRatio)); 254 } 255 256 scaleX = scaledTextureWidth / width; 257 scaleY = scaledTextureHeight / height; 258 259 // TODO: Need a better way to find out whether currently in landscape 260 boolean landscape = width > height; 261 if (landscape) { 262 matrix.setScale(scaleX, scaleY, 0f, (float) height / 2); 263 } else { 264 matrix.setScale(scaleX, scaleY, (float) width / 2, 0.0f); 265 } 266 setPreviewTransformMatrix(matrix); 267 adjustBottomBar(width, height, bottomBar, bottomBarOptimalHeight, scaledTextureWidth, 268 scaledTextureHeight, landscape); 269 } 270 271 private void adjustBottomBar(int width, int height, BottomBar bottomBar, 272 int bottomBarOptimalHeight, float scaledTextureWidth, 273 float scaledTextureHeight, boolean landscape) { 274 float previewAspectRatio = 275 scaledTextureWidth / scaledTextureHeight; 276 if (previewAspectRatio < 1.0) { 277 previewAspectRatio = 1.0f/previewAspectRatio; 278 } 279 float screenAspectRatio = (float)width / (float)height; 280 if (screenAspectRatio < 1.0) { 281 screenAspectRatio = 1.0f/screenAspectRatio; 282 } 283 284 if(bottomBar != null) { 285 LayoutParams lp = (LayoutParams) bottomBar.getLayoutParams(); 286 // TODO accoount for cases where resizes bar height would be < bottomBarMinHeight 287 if (previewAspectRatio >= screenAspectRatio) { 288 bottomBar.setAlpha(0.5f); 289 if (landscape) { 290 lp.width = bottomBarOptimalHeight; 291 lp.height = LayoutParams.MATCH_PARENT; 292 } else { 293 lp.height = bottomBarOptimalHeight; 294 lp.width = LayoutParams.MATCH_PARENT; 295 } 296 } else { 297 bottomBar.setAlpha(1.0f); 298 if (landscape) { 299 lp.width = (int)(width - scaledTextureWidth); 300 lp.height = LayoutParams.MATCH_PARENT; 301 } else { 302 lp.height = (int)(height - scaledTextureHeight); 303 lp.width = LayoutParams.MATCH_PARENT; 304 } 305 } 306 bottomBar.setLayoutParams(lp); 307 } 308 } 309 310 /** 311 * This is to support modules that calculate their own transform matrix because 312 * they need to use a transform matrix to rotate the preview. 313 * 314 * @param width width of the TextureView where preview is hosted 315 * @param height height of the TextureView where preview is hosted 316 * @param matrix transform matrix to be set on the TextureView 317 */ 318 public void updatePreviewTransform(int width, int height, Matrix matrix) { 319 if (width == 0 || height == 0) { 320 Log.e(TAG, "Invalid screen size: " + width + " x " + height); 321 return; 322 } 323 int bottomBarMinHeight = mCameraRootView.getResources() 324 .getDimensionPixelSize(R.dimen.bottom_bar_height_min); 325 int bottomBarOptimalHeight = mCameraRootView.getResources() 326 .getDimensionPixelSize(R.dimen.bottom_bar_height_optimal); 327 RectF previewRect = new RectF(0, 0, width, height); 328 matrix.mapRect(previewRect); 329 330 float previewWidth = previewRect.width(); 331 float previewHeight = previewRect.height(); 332 if (previewHeight == 0 || previewWidth == 0) { 333 Log.e(TAG, "Invalid preview size: " + previewWidth + " x " + previewHeight); 334 return; 335 } 336 337 BottomBar bottomBar = (BottomBar) mCameraRootView.findViewById(R.id.bottom_bar); 338 setPreviewTransformMatrix(matrix); 339 adjustBottomBar(width, height, bottomBar, bottomBarOptimalHeight, previewWidth, 340 previewHeight, width > height); 341 } 342 343 public interface AnimationFinishedListener { 344 public void onAnimationFinished(boolean success); 345 } 346 347 private class MyTouchListener implements View.OnTouchListener { 348 private boolean mScaleStarted = false; 349 @Override 350 public boolean onTouch(View v, MotionEvent event) { 351 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 352 mScaleStarted = false; 353 } else if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { 354 mScaleStarted = true; 355 } 356 return (!mScaleStarted) && mGestureDetector.onTouchEvent(event); 357 } 358 } 359 360 /** 361 * This gesture listener finds out the direction of the scroll gestures and 362 * sends them to CameraAppUI to do further handling. 363 */ 364 private class MyGestureListener extends GestureDetector.SimpleOnGestureListener { 365 private MotionEvent mDown; 366 367 @Override 368 public boolean onScroll(MotionEvent e1, MotionEvent ev, float distanceX, float distanceY) { 369 if (ev.getEventTime() - ev.getDownTime() > SWIPE_TIME_OUT_MS 370 || mSwipeState != IDLE) { 371 return false; 372 } 373 374 int deltaX = (int) (ev.getX() - mDown.getX()); 375 int deltaY = (int) (ev.getY() - mDown.getY()); 376 if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) { 377 if (Math.abs(deltaX) > mSlop || Math.abs(deltaY) > mSlop) { 378 // Calculate the direction of the swipe. 379 if (deltaX >= Math.abs(deltaY)) { 380 // Swipe right. 381 setSwipeState(SWIPE_RIGHT); 382 } else if (deltaX <= -Math.abs(deltaY)) { 383 // Swipe left. 384 setSwipeState(SWIPE_LEFT); 385 } else if (deltaY >= Math.abs(deltaX)) { 386 // Swipe down. 387 setSwipeState(SWIPE_DOWN); 388 } else if (deltaY <= -Math.abs(deltaX)) { 389 // Swipe up. 390 setSwipeState(SWIPE_UP); 391 } 392 } 393 } 394 return true; 395 } 396 397 private void setSwipeState(int swipeState) { 398 mSwipeState = swipeState; 399 // Notify new swipe detected. 400 onSwipeDetected(swipeState); 401 } 402 403 @Override 404 public boolean onDown(MotionEvent ev) { 405 mDown = MotionEvent.obtain(ev); 406 mSwipeState = IDLE; 407 return false; 408 } 409 } 410 411 public CameraAppUI(AppController controller, MainActivityLayout appRootView, 412 boolean isSecureCamera, boolean isCaptureIntent) { 413 mSlop = ViewConfiguration.get(controller.getAndroidContext()).getScaledTouchSlop(); 414 mController = controller; 415 mIsSecureCamera = isSecureCamera; 416 mIsCaptureIntent = isCaptureIntent; 417 418 mAppRootView = appRootView; 419 mFilmstripLayout = (FilmstripLayout) appRootView.findViewById(R.id.filmstrip_layout); 420 mCameraRootView = (FrameLayout) appRootView.findViewById(R.id.camera_app_root); 421 mModeTransitionView = (ModeTransitionView) 422 mAppRootView.findViewById(R.id.mode_transition_view); 423 mFilmstripBottomControls = new FilmstripBottomControls( 424 (ViewGroup) mAppRootView.findViewById(R.id.filmstrip_bottom_controls)); 425 mFilmstripPanel = (FilmstripContentPanel) mAppRootView.findViewById(R.id.filmstrip_layout); 426 mGestureDetector = new GestureDetector(controller.getAndroidContext(), 427 new MyGestureListener()); 428 mModeListView = (ModeListView) appRootView.findViewById(R.id.mode_list_layout); 429 if (mModeListView != null) { 430 mModeListView.setModeSwitchListener(this); 431 } else { 432 Log.e(TAG, "Cannot find mode list in the view hierarchy"); 433 } 434 mAnimationManager = new AnimationManager(); 435 } 436 437 /** 438 * Redirects touch events to appropriate recipient views based on swipe direction. 439 * More specifically, swipe up and swipe down will be handled by the view that handles 440 * mode transition; swipe left will be send to filmstrip; swipe right will be redirected 441 * to mode list in order to bring up mode list. 442 */ 443 private void onSwipeDetected(int swipeState) { 444 if (swipeState == SWIPE_UP || swipeState == SWIPE_DOWN) { 445 // Quick switch between photo/video. 446 if (mController.getCurrentModuleIndex() == ModeListView.MODE_PHOTO || 447 mController.getCurrentModuleIndex() == ModeListView.MODE_VIDEO) { 448 mAppRootView.redirectTouchEventsTo(mModeTransitionView); 449 450 final int moduleToTransitionTo = 451 mController.getCurrentModuleIndex() == ModeListView.MODE_PHOTO ? 452 ModeListView.MODE_VIDEO : ModeListView.MODE_PHOTO; 453 int shadeColorId = ModeListView.getModeThemeColor(moduleToTransitionTo); 454 int iconRes = ModeListView.getModeIconResourceId(moduleToTransitionTo); 455 456 AnimationFinishedListener listener = new AnimationFinishedListener() { 457 @Override 458 public void onAnimationFinished(boolean success) { 459 if (success) { 460 mHideCoverRunnable = new Runnable() { 461 @Override 462 public void run() { 463 mModeTransitionView.startPeepHoleAnimation(); 464 } 465 }; 466 mModeCoverState = COVER_SHOWN; 467 // Go to new module when the previous operation is successful. 468 mController.onModeSelected(moduleToTransitionTo); 469 } 470 } 471 }; 472 if (mSwipeState == SWIPE_UP) { 473 mModeTransitionView.prepareToPullUpShade(shadeColorId, iconRes, listener); 474 } else { 475 mModeTransitionView.prepareToPullDownShade(shadeColorId, iconRes, listener); 476 } 477 } 478 } else if (swipeState == SWIPE_LEFT) { 479 // Pass the touch sequence to filmstrip layout. 480 mAppRootView.redirectTouchEventsTo(mFilmstripLayout); 481 482 } else if (swipeState == SWIPE_RIGHT) { 483 // Pass the touch to mode switcher 484 mAppRootView.redirectTouchEventsTo(mModeListView); 485 } 486 } 487 488 /** 489 * Gets called when activity resumes in preview. 490 */ 491 public void resume() { 492 if (mTextureView == null || mTextureView.getSurfaceTexture() != null) { 493 mModeListView.startAccordionAnimationWithDelay(SHIMMY_DELAY_MS); 494 } else { 495 // Show mode theme cover until preview is ready 496 showModeCoverUntilPreviewReady(); 497 } 498 // Hide action bar first since we are in full screen mode first, and 499 // switch the system UI to lights-out mode. 500 mFilmstripPanel.hide(); 501 } 502 503 /** 504 * A cover view showing the mode theme color and mode icon will be visible on 505 * top of preview until preview is ready (i.e. camera preview is started and 506 * the first frame has been received). 507 */ 508 private void showModeCoverUntilPreviewReady() { 509 int modeId = mController.getCurrentModuleIndex(); 510 int colorId = ModeListView.getModeThemeColor(modeId); 511 int iconId = ModeListView.getModeIconResourceId(modeId); 512 mModeTransitionView.setupModeCover(colorId, iconId); 513 mHideCoverRunnable = new Runnable() { 514 @Override 515 public void run() { 516 mModeTransitionView.hideModeCover(new AnimationFinishedListener() { 517 @Override 518 public void onAnimationFinished(boolean success) { 519 if (success) { 520 // Show shimmy in SHIMMY_DELAY_MS 521 mModeListView.startAccordionAnimationWithDelay(SHIMMY_DELAY_MS); 522 } 523 } 524 }); 525 } 526 }; 527 mModeCoverState = COVER_SHOWN; 528 } 529 530 private void hideModeCover() { 531 if (mHideCoverRunnable != null) { 532 mAppRootView.post(mHideCoverRunnable); 533 mHideCoverRunnable = null; 534 } 535 mModeCoverState = COVER_HIDDEN; 536 } 537 538 /** 539 * Called when the back key is pressed. 540 * 541 * @return Whether the UI responded to the key event. 542 */ 543 public boolean onBackPressed() { 544 return mFilmstripLayout.onBackPressed(); 545 } 546 547 /** 548 * Sets a {@link com.android.camera.ui.PreviewStatusListener} that 549 * listens to SurfaceTexture changes. In addition, the listener will also provide 550 * a {@link android.view.GestureDetector.OnGestureListener}, which will listen to 551 * gestures that happen on camera preview. 552 * 553 * @param previewStatusListener the listener that gets notified when SurfaceTexture 554 * changes 555 */ 556 public void setPreviewStatusListener(PreviewStatusListener previewStatusListener) { 557 mPreviewStatusListener = previewStatusListener; 558 if (mPreviewStatusListener != null) { 559 GestureDetector.OnGestureListener gestureListener 560 = mPreviewStatusListener.getGestureListener(); 561 if (gestureListener != null) { 562 mPreviewOverlay.setGestureListener(gestureListener); 563 } 564 } 565 } 566 567 /** 568 * This inflates generic_module layout, which contains all the shared views across 569 * modules. Then each module inflates their own views in the given view group. For 570 * now, this is called every time switching from a not-yet-refactored module to a 571 * refactored module. In the future, this should only need to be done once per app 572 * start. 573 */ 574 public void prepareModuleUI() { 575 mCameraRootView.removeAllViews(); 576 LayoutInflater inflater = (LayoutInflater) mController.getAndroidContext() 577 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 578 inflater.inflate(R.layout.generic_module, mCameraRootView, true); 579 580 mModuleUI = (FrameLayout) mCameraRootView.findViewById(R.id.module_layout); 581 mTextureView = (TextureView) mCameraRootView.findViewById(R.id.preview_content); 582 mTextureView.addOnLayoutChangeListener(mPreviewLayoutChangeListener); 583 mTextureView.setSurfaceTextureListener(this); 584 mPreviewOverlay = (PreviewOverlay) mCameraRootView.findViewById(R.id.preview_overlay); 585 mPreviewOverlay.setOnTouchListener(new MyTouchListener()); 586 mCaptureOverlay = (CaptureAnimationOverlay) 587 mCameraRootView.findViewById(R.id.capture_overlay); 588 } 589 590 // TODO: Remove this when refactor is done. 591 // This is here to ensure refactored modules can work with not-yet-refactored ones. 592 public void clearCameraUI() { 593 mCameraRootView.removeAllViews(); 594 mModuleUI = null; 595 mTextureView.removeOnLayoutChangeListener(mPreviewLayoutChangeListener); 596 mTextureView = null; 597 mPreviewOverlay = null; 598 mFlashOverlay = null; 599 } 600 601 /** 602 * Called indirectly from each module in their initialization to get a view group 603 * to inflate the module specific views in. 604 * 605 * @return a view group for modules to attach views to 606 */ 607 public FrameLayout getModuleRootView() { 608 // TODO: Change it to mModuleUI when refactor is done 609 return mCameraRootView; 610 } 611 612 /** 613 * Remove all the module specific views. 614 */ 615 public void clearModuleUI() { 616 if (mModuleUI != null) { 617 mModuleUI.removeAllViews(); 618 } 619 620 mPreviewStatusListener = null; 621 mPreviewOverlay.reset(); 622 } 623 624 /** 625 * Gets called when preview is started. 626 */ 627 public void onPreviewStarted() { 628 if (mModeCoverState == COVER_SHOWN) { 629 mModeCoverState = COVER_WILL_HIDE_AT_NEXT_FRAME; 630 } 631 } 632 633 /** 634 * Gets called when a mode is selected from {@link com.android.camera.ui.ModeListView} 635 * 636 * @param modeIndex mode index of the selected mode 637 */ 638 @Override 639 public void onModeSelected(int modeIndex) { 640 mHideCoverRunnable = new Runnable() { 641 @Override 642 public void run() { 643 mModeListView.startModeSelectionAnimation(); 644 } 645 }; 646 mModeCoverState = COVER_SHOWN; 647 648 int lastIndex = mController.getCurrentModuleIndex(); 649 mController.onModeSelected(modeIndex); 650 int currentIndex = mController.getCurrentModuleIndex(); 651 652 if (mTextureView == null) { 653 // TODO: Remove this when all the modules use TextureView 654 int temporaryDelay = 600; // ms 655 mModeListView.postDelayed(new Runnable() { 656 @Override 657 public void run() { 658 hideModeCover(); 659 } 660 }, temporaryDelay); 661 } else if (lastIndex == currentIndex) { 662 hideModeCover(); 663 } 664 } 665 666 /** 667 * Sets the transform matrix on the preview TextureView 668 */ 669 public void setPreviewTransformMatrix(Matrix transformMatrix) { 670 if (mTextureView == null) { 671 throw new UnsupportedOperationException("Cannot set transform matrix on a null" + 672 " TextureView"); 673 } 674 mTextureView.setTransform(transformMatrix); 675 } 676 677 678 /********************** Capture animation **********************/ 679 /* TODO: This session is subject to UX changes. In addition to the generic 680 flash animation and post capture animation, consider designating a parameter 681 for specifying the type of animation, as well as an animation finished listener 682 so that modules can have more knowledge of the status of the animation. */ 683 684 /** 685 * Starts the pre-capture animation. 686 */ 687 public void startPreCaptureAnimation() { 688 mCaptureOverlay.startFlashAnimation(); 689 } 690 691 /** 692 * Cancels the pre-capture animation. 693 */ 694 public void cancelPreCaptureAnimation() { 695 mAnimationManager.cancelAnimations(); 696 } 697 698 /** 699 * Cancels the post-capture animation. 700 */ 701 public void cancelPostCaptureAnimation() { 702 mAnimationManager.cancelAnimations(); 703 } 704 705 public FilmstripContentPanel getFilmstripContentPanel() { 706 return mFilmstripPanel; 707 } 708 709 /** 710 * @return The {@link com.android.camera.app.CameraAppUI.BottomControls} on the 711 * bottom of the filmstrip. 712 */ 713 public BottomControls getFilmstripBottomControls() { 714 return mFilmstripBottomControls; 715 } 716 717 /** 718 * @param listener The listener for bottom controls. 719 */ 720 public void setFilmstripBottomControlsListener(BottomControls.Listener listener) { 721 mFilmstripBottomControls.setListener(listener); 722 } 723 724 /***************************SurfaceTexture Listener*********************************/ 725 726 @Override 727 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 728 Log.v(TAG, "SurfaceTexture is available"); 729 if (mPreviewStatusListener != null) { 730 mPreviewStatusListener.onSurfaceTextureAvailable(surface, width, height); 731 } 732 } 733 734 @Override 735 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 736 if (mPreviewStatusListener != null) { 737 mPreviewStatusListener.onSurfaceTextureSizeChanged(surface, width, height); 738 } 739 } 740 741 @Override 742 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 743 Log.v(TAG, "SurfaceTexture is destroyed"); 744 if (mPreviewStatusListener != null) { 745 return mPreviewStatusListener.onSurfaceTextureDestroyed(surface); 746 } 747 return false; 748 } 749 750 @Override 751 public void onSurfaceTextureUpdated(SurfaceTexture surface) { 752 if (mModeCoverState == COVER_WILL_HIDE_AT_NEXT_FRAME) { 753 hideModeCover(); 754 mModeCoverState = COVER_HIDDEN; 755 } 756 if (mPreviewStatusListener != null) { 757 mPreviewStatusListener.onSurfaceTextureUpdated(surface); 758 } 759 } 760} 761