CameraAppUI.java revision e038c161389b5d1c0476e315736df31562328894
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 float previewAspectRatio = 234 (float)scaledTextureWidth / (float)scaledTextureHeight; 235 if (previewAspectRatio < 1.0) { 236 previewAspectRatio = 1.0f/previewAspectRatio; 237 } 238 float screenAspectRatio = (float)width / (float)height; 239 if (screenAspectRatio < 1.0) { 240 screenAspectRatio = 1.0f/screenAspectRatio; 241 } 242 243 if(bottomBar != null) { 244 LayoutParams lp = (LayoutParams) bottomBar.getLayoutParams(); 245 // TODO accoount for cases where resizes bar height would be < bottomBarMinHeight 246 if (previewAspectRatio >= screenAspectRatio) { 247 bottomBar.setAlpha(0.5f); 248 if (landscape) { 249 lp.width = bottomBarOptimalHeight; 250 lp.height = LayoutParams.MATCH_PARENT; 251 } else { 252 lp.height = bottomBarOptimalHeight; 253 lp.width = LayoutParams.MATCH_PARENT; 254 } 255 } else { 256 bottomBar.setAlpha(1.0f); 257 if (landscape) { 258 lp.width = (int)((float) width - scaledTextureWidth); 259 lp.height = LayoutParams.MATCH_PARENT; 260 } else { 261 lp.height = (int)((float) height - scaledTextureHeight); 262 lp.width = LayoutParams.MATCH_PARENT; 263 } 264 } 265 bottomBar.setLayoutParams(lp); 266 } 267 } 268 269 public interface AnimationFinishedListener { 270 public void onAnimationFinished(boolean success); 271 } 272 273 private class MyTouchListener implements View.OnTouchListener { 274 private boolean mScaleStarted = false; 275 @Override 276 public boolean onTouch(View v, MotionEvent event) { 277 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 278 mScaleStarted = false; 279 } else if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { 280 mScaleStarted = true; 281 } 282 return (!mScaleStarted) && mGestureDetector.onTouchEvent(event); 283 } 284 } 285 286 /** 287 * This gesture listener finds out the direction of the scroll gestures and 288 * sends them to CameraAppUI to do further handling. 289 */ 290 private class MyGestureListener extends GestureDetector.SimpleOnGestureListener { 291 private MotionEvent mDown; 292 293 @Override 294 public boolean onScroll(MotionEvent e1, MotionEvent ev, float distanceX, float distanceY) { 295 if (ev.getEventTime() - ev.getDownTime() > SWIPE_TIME_OUT_MS 296 || mSwipeState != IDLE) { 297 return false; 298 } 299 300 int deltaX = (int) (ev.getX() - mDown.getX()); 301 int deltaY = (int) (ev.getY() - mDown.getY()); 302 if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) { 303 if (Math.abs(deltaX) > mSlop || Math.abs(deltaY) > mSlop) { 304 // Calculate the direction of the swipe. 305 if (deltaX >= Math.abs(deltaY)) { 306 // Swipe right. 307 setSwipeState(SWIPE_RIGHT); 308 } else if (deltaX <= -Math.abs(deltaY)) { 309 // Swipe left. 310 setSwipeState(SWIPE_LEFT); 311 } else if (deltaY >= Math.abs(deltaX)) { 312 // Swipe down. 313 setSwipeState(SWIPE_DOWN); 314 } else if (deltaY <= -Math.abs(deltaX)) { 315 // Swipe up. 316 setSwipeState(SWIPE_UP); 317 } 318 } 319 } 320 return true; 321 } 322 323 private void setSwipeState(int swipeState) { 324 mSwipeState = swipeState; 325 // Notify new swipe detected. 326 onSwipeDetected(swipeState); 327 } 328 329 @Override 330 public boolean onDown(MotionEvent ev) { 331 mDown = MotionEvent.obtain(ev); 332 mSwipeState = IDLE; 333 return false; 334 } 335 } 336 337 public CameraAppUI(AppController controller, MainActivityLayout appRootView, 338 boolean isSecureCamera, boolean isCaptureIntent) { 339 mSlop = ViewConfiguration.get(controller.getAndroidContext()).getScaledTouchSlop(); 340 mController = controller; 341 mIsSecureCamera = isSecureCamera; 342 mIsCaptureIntent = isCaptureIntent; 343 344 mAppRootView = appRootView; 345 mFilmstripLayout = (FilmstripLayout) appRootView.findViewById(R.id.filmstrip_layout); 346 mCameraRootView = (FrameLayout) appRootView.findViewById(R.id.camera_app_root); 347 mModeTransitionView = (ModeTransitionView) 348 mAppRootView.findViewById(R.id.mode_transition_view); 349 mFilmstripBottomControls = new FilmstripBottomControls( 350 (ViewGroup) mAppRootView.findViewById(R.id.filmstrip_bottom_controls)); 351 mFilmstripPanel = (FilmstripContentPanel) mAppRootView.findViewById(R.id.filmstrip_layout); 352 mGestureDetector = new GestureDetector(controller.getAndroidContext(), 353 new MyGestureListener()); 354 mModeListView = (ModeListView) appRootView.findViewById(R.id.mode_list_layout); 355 if (mModeListView != null) { 356 mModeListView.setModeSwitchListener(this); 357 } else { 358 Log.e(TAG, "Cannot find mode list in the view hierarchy"); 359 } 360 mAnimationManager = new AnimationManager(); 361 } 362 363 /** 364 * Redirects touch events to appropriate recipient views based on swipe direction. 365 * More specifically, swipe up and swipe down will be handled by the view that handles 366 * mode transition; swipe left will be send to filmstrip; swipe right will be redirected 367 * to mode list in order to bring up mode list. 368 */ 369 private void onSwipeDetected(int swipeState) { 370 if (swipeState == SWIPE_UP || swipeState == SWIPE_DOWN) { 371 // Quick switch between photo/video. 372 if (mController.getCurrentModuleIndex() == ModeListView.MODE_PHOTO || 373 mController.getCurrentModuleIndex() == ModeListView.MODE_VIDEO) { 374 mAppRootView.redirectTouchEventsTo(mModeTransitionView); 375 376 final int moduleToTransitionTo = 377 mController.getCurrentModuleIndex() == ModeListView.MODE_PHOTO ? 378 ModeListView.MODE_VIDEO : ModeListView.MODE_PHOTO; 379 int shadeColorId = ModeListView.getModeThemeColor(moduleToTransitionTo); 380 int iconRes = ModeListView.getModeIconResourceId(moduleToTransitionTo); 381 382 AnimationFinishedListener listener = new AnimationFinishedListener() { 383 public void onAnimationFinished(boolean success) { 384 if (success) { 385 mHideCoverRunnable = new Runnable() { 386 @Override 387 public void run() { 388 mModeTransitionView.startPeepHoleAnimation(); 389 } 390 }; 391 mModeCoverState = COVER_SHOWN; 392 // Go to new module when the previous operation is successful. 393 mController.onModeSelected(moduleToTransitionTo); 394 } 395 } 396 }; 397 if (mSwipeState == SWIPE_UP) { 398 mModeTransitionView.prepareToPullUpShade(shadeColorId, iconRes, listener); 399 } else { 400 mModeTransitionView.prepareToPullDownShade(shadeColorId, iconRes, listener); 401 } 402 } 403 } else if (swipeState == SWIPE_LEFT) { 404 // Pass the touch sequence to filmstrip layout. 405 mAppRootView.redirectTouchEventsTo(mFilmstripLayout); 406 407 } else if (swipeState == SWIPE_RIGHT) { 408 // Pass the touch to mode switcher 409 mAppRootView.redirectTouchEventsTo(mModeListView); 410 } 411 } 412 413 /** 414 * Gets called when activity resumes in preview. 415 */ 416 public void resume() { 417 if (mTextureView == null || mTextureView.getSurfaceTexture() != null) { 418 mModeListView.startAccordionAnimationWithDelay(SHIMMY_DELAY_MS); 419 } else { 420 // Show mode theme cover until preview is ready 421 showModeCoverUntilPreviewReady(); 422 } 423 // Hide action bar first since we are in full screen mode first, and 424 // switch the system UI to lights-out mode. 425 mFilmstripPanel.hide(); 426 } 427 428 /** 429 * A cover view showing the mode theme color and mode icon will be visible on 430 * top of preview until preview is ready (i.e. camera preview is started and 431 * the first frame has been received). 432 */ 433 private void showModeCoverUntilPreviewReady() { 434 int modeId = mController.getCurrentModuleIndex(); 435 int colorId = ModeListView.getModeThemeColor(modeId); 436 int iconId = ModeListView.getModeIconResourceId(modeId); 437 mModeTransitionView.setupModeCover(colorId, iconId); 438 mHideCoverRunnable = new Runnable() { 439 @Override 440 public void run() { 441 mModeTransitionView.hideModeCover(new AnimationFinishedListener() { 442 @Override 443 public void onAnimationFinished(boolean success) { 444 if (success) { 445 // Show shimmy in SHIMMY_DELAY_MS 446 mModeListView.startAccordionAnimationWithDelay(SHIMMY_DELAY_MS); 447 } 448 } 449 }); 450 } 451 }; 452 mModeCoverState = COVER_SHOWN; 453 } 454 455 private void hideModeCover() { 456 if (mHideCoverRunnable != null) { 457 mAppRootView.post(mHideCoverRunnable); 458 mHideCoverRunnable = null; 459 } 460 mModeCoverState = COVER_HIDDEN; 461 } 462 463 /** 464 * Called when the back key is pressed. 465 * 466 * @return Whether the UI responded to the key event. 467 */ 468 public boolean onBackPressed() { 469 return mFilmstripLayout.onBackPressed(); 470 } 471 472 /** 473 * Sets a {@link com.android.camera.ui.PreviewStatusListener} that 474 * listens to SurfaceTexture changes. In addition, the listener will also provide 475 * a {@link android.view.GestureDetector.OnGestureListener}, which will listen to 476 * gestures that happen on camera preview. 477 * 478 * @param previewStatusListener the listener that gets notified when SurfaceTexture 479 * changes 480 */ 481 public void setPreviewStatusListener(PreviewStatusListener previewStatusListener) { 482 mPreviewStatusListener = previewStatusListener; 483 if (mPreviewStatusListener != null) { 484 GestureDetector.OnGestureListener gestureListener 485 = mPreviewStatusListener.getGestureListener(); 486 if (gestureListener != null) { 487 mPreviewOverlay.setGestureListener(gestureListener); 488 } 489 } 490 } 491 492 /** 493 * This inflates generic_module layout, which contains all the shared views across 494 * modules. Then each module inflates their own views in the given view group. For 495 * now, this is called every time switching from a not-yet-refactored module to a 496 * refactored module. In the future, this should only need to be done once per app 497 * start. 498 */ 499 public void prepareModuleUI() { 500 mCameraRootView.removeAllViews(); 501 LayoutInflater inflater = (LayoutInflater) mController.getAndroidContext() 502 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 503 inflater.inflate(R.layout.generic_module, mCameraRootView, true); 504 505 mModuleUI = (FrameLayout) mCameraRootView.findViewById(R.id.module_layout); 506 mTextureView = (TextureView) mCameraRootView.findViewById(R.id.preview_content); 507 mTextureView.setSurfaceTextureListener(this); 508 mPreviewOverlay = (PreviewOverlay) mCameraRootView.findViewById(R.id.preview_overlay); 509 mPreviewOverlay.setOnTouchListener(new MyTouchListener()); 510 mCaptureOverlay = (CaptureAnimationOverlay) 511 mCameraRootView.findViewById(R.id.capture_overlay); 512 mPreviewThumbView = (ImageView) mCameraRootView.findViewById(R.id.preview_thumb); 513 514 } 515 516 // TODO: Remove this when refactor is done. 517 // This is here to ensure refactored modules can work with not-yet-refactored ones. 518 public void clearCameraUI() { 519 mCameraRootView.removeAllViews(); 520 mModuleUI = null; 521 mTextureView = null; 522 mPreviewOverlay = null; 523 mFlashOverlay = null; 524 } 525 526 /** 527 * Called indirectly from each module in their initialization to get a view group 528 * to inflate the module specific views in. 529 * 530 * @return a view group for modules to attach views to 531 */ 532 public FrameLayout getModuleRootView() { 533 // TODO: Change it to mModuleUI when refactor is done 534 return mCameraRootView; 535 } 536 537 /** 538 * Remove all the module specific views. 539 */ 540 public void clearModuleUI() { 541 if (mModuleUI != null) { 542 mModuleUI.removeAllViews(); 543 } 544 545 // TODO: Bring TextureView up to the app level 546 mTextureView.removeOnLayoutChangeListener(null); 547 548 mPreviewStatusListener = null; 549 mPreviewOverlay.reset(); 550 } 551 552 /** 553 * Gets called when preview is started. 554 */ 555 public void onPreviewStarted() { 556 if (mModeCoverState == COVER_SHOWN) { 557 mModeCoverState = COVER_WILL_HIDE_AT_NEXT_FRAME; 558 } 559 } 560 561 /** 562 * Gets called when a mode is selected from {@link com.android.camera.ui.ModeListView} 563 * 564 * @param modeIndex mode index of the selected mode 565 */ 566 @Override 567 public void onModeSelected(int modeIndex) { 568 mHideCoverRunnable = new Runnable() { 569 @Override 570 public void run() { 571 mModeListView.startModeSelectionAnimation(); 572 } 573 }; 574 mModeCoverState = COVER_SHOWN; 575 576 int lastIndex = mController.getCurrentModuleIndex(); 577 mController.onModeSelected(modeIndex); 578 int currentIndex = mController.getCurrentModuleIndex(); 579 580 if (mTextureView == null) { 581 // TODO: Remove this when all the modules use TextureView 582 int temporaryDelay = 600; // ms 583 mModeListView.postDelayed(new Runnable() { 584 @Override 585 public void run() { 586 hideModeCover(); 587 } 588 }, temporaryDelay); 589 } else if (lastIndex == currentIndex) { 590 hideModeCover(); 591 } 592 } 593 594 /** 595 * Sets the transform matrix on the preview TextureView 596 */ 597 public void setPreviewTransformMatrix(Matrix transformMatrix) { 598 if (mTextureView == null) { 599 throw new UnsupportedOperationException("Cannot set transform matrix on a null" + 600 " TextureView"); 601 } 602 mTextureView.setTransform(transformMatrix); 603 } 604 605 606 /********************** Capture animation **********************/ 607 /* TODO: This session is subject to UX changes. In addition to the generic 608 flash animation and post capture animation, consider designating a parameter 609 for specifying the type of animation, as well as an animation finished listener 610 so that modules can have more knowledge of the status of the animation. */ 611 612 /** 613 * Starts the pre-capture animation. 614 */ 615 public void startPreCaptureAnimation() { 616 mCaptureOverlay.startFlashAnimation(); 617 } 618 619 /** 620 * Cancels the pre-capture animation. 621 */ 622 public void cancelPreCaptureAnimation() { 623 mAnimationManager.cancelAnimations(); 624 } 625 626 /** 627 * Starts the post-capture animation with the current preview image. 628 */ 629 public void startPostCaptureAnimation() { 630 if (mTextureView == null) { 631 Log.e(TAG, "Cannot get a frame from a null TextureView for animation"); 632 return; 633 } 634 // TODO: Down sample bitmap 635 startPostCaptureAnimation(mTextureView.getBitmap()); 636 } 637 638 /** 639 * Starts the post-capture animation with the given thumbnail. 640 * 641 * @param thumbnail The thumbnail for the animation. 642 */ 643 public void startPostCaptureAnimation(Bitmap thumbnail) { 644 mPreviewThumbView.setImageBitmap(thumbnail); 645 mAnimationManager.startCaptureAnimation(mPreviewThumbView); 646 } 647 648 /** 649 * Cancels the post-capture animation. 650 */ 651 public void cancelPostCaptureAnimation() { 652 mAnimationManager.cancelAnimations(); 653 } 654 655 public FilmstripContentPanel getFilmstripContentPanel() { 656 return mFilmstripPanel; 657 } 658 659 /** 660 * @return The {@link com.android.camera.app.CameraAppUI.BottomControls} on the 661 * bottom of the filmstrip. 662 */ 663 public BottomControls getFilmstripBottomControls() { 664 return mFilmstripBottomControls; 665 } 666 667 /** 668 * @param listener The listener for bottom controls. 669 */ 670 public void setFilmstripBottomControlsListener(BottomControls.Listener listener) { 671 mFilmstripBottomControls.setListener(listener); 672 } 673 674 /***************************SurfaceTexture Listener*********************************/ 675 676 @Override 677 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 678 Log.v(TAG, "SurfaceTexture is available"); 679 if (mPreviewStatusListener != null) { 680 mPreviewStatusListener.onSurfaceTextureAvailable(surface, width, height); 681 } 682 } 683 684 @Override 685 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 686 if (mPreviewStatusListener != null) { 687 mPreviewStatusListener.onSurfaceTextureSizeChanged(surface, width, height); 688 } 689 } 690 691 @Override 692 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 693 Log.v(TAG, "SurfaceTexture is destroyed"); 694 if (mPreviewStatusListener != null) { 695 return mPreviewStatusListener.onSurfaceTextureDestroyed(surface); 696 } 697 return false; 698 } 699 700 @Override 701 public void onSurfaceTextureUpdated(SurfaceTexture surface) { 702 if (mModeCoverState == COVER_WILL_HIDE_AT_NEXT_FRAME) { 703 hideModeCover(); 704 mModeCoverState = COVER_HIDDEN; 705 } 706 if (mPreviewStatusListener != null) { 707 mPreviewStatusListener.onSurfaceTextureUpdated(surface); 708 } 709 } 710} 711