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