1 /* 2 * Copyright (C) 2012 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 17 package com.android.camera; 18 19 import android.graphics.Bitmap; 20 import android.graphics.Color; 21 import android.graphics.Matrix; 22 import android.graphics.SurfaceTexture; 23 import android.graphics.drawable.ColorDrawable; 24 import android.hardware.Camera.Parameters; 25 import android.os.Handler; 26 import android.os.Message; 27 import android.util.Log; 28 import android.view.Gravity; 29 import android.view.SurfaceHolder; 30 import android.view.SurfaceView; 31 import android.view.TextureView; 32 import android.view.TextureView.SurfaceTextureListener; 33 import android.view.View; 34 import android.view.View.OnClickListener; 35 import android.view.View.OnLayoutChangeListener; 36 import android.view.ViewGroup; 37 import android.widget.FrameLayout.LayoutParams; 38 import android.widget.ImageView; 39 import android.widget.LinearLayout; 40 import android.widget.PopupWindow; 41 import android.widget.TextView; 42 43 import com.android.camera.CameraPreference.OnPreferenceChangedListener; 44 import com.android.camera.ui.AbstractSettingPopup; 45 import com.android.camera.ui.CameraControls; 46 import com.android.camera.ui.CameraRootView; 47 import com.android.camera.ui.ModuleSwitcher; 48 import com.android.camera.ui.PieRenderer; 49 import com.android.camera.ui.RenderOverlay; 50 import com.android.camera.ui.RotateLayout; 51 import com.android.camera.ui.ZoomRenderer; 52 import com.android.camera.util.CameraUtil; 53 import com.android.camera2.R; 54 55 import java.util.List; 56 57 public class VideoUI implements PieRenderer.PieListener, 58 PreviewGestures.SingleTapListener, 59 CameraRootView.MyDisplayListener, 60 SurfaceTextureListener, SurfaceHolder.Callback { 61 private static final String TAG = "CAM_VideoUI"; 62 private static final int UPDATE_TRANSFORM_MATRIX = 1; 63 // module fields 64 private CameraActivity mActivity; 65 private View mRootView; 66 private TextureView mTextureView; 67 // An review image having same size as preview. It is displayed when 68 // recording is stopped in capture intent. 69 private ImageView mReviewImage; 70 private View mReviewCancelButton; 71 private View mReviewDoneButton; 72 private View mReviewPlayButton; 73 private ShutterButton mShutterButton; 74 private ModuleSwitcher mSwitcher; 75 private TextView mRecordingTimeView; 76 private LinearLayout mLabelsLinearLayout; 77 private View mTimeLapseLabel; 78 private RenderOverlay mRenderOverlay; 79 private PieRenderer mPieRenderer; 80 private VideoMenu mVideoMenu; 81 private CameraControls mCameraControls; 82 private SettingsPopup mPopup; 83 private ZoomRenderer mZoomRenderer; 84 private PreviewGestures mGestures; 85 private View mMenuButton; 86 private OnScreenIndicators mOnScreenIndicators; 87 private RotateLayout mRecordingTimeRect; 88 private boolean mRecordingStarted = false; 89 private SurfaceTexture mSurfaceTexture; 90 private VideoController mController; 91 private int mZoomMax; 92 private List<Integer> mZoomRatios; 93 private View mPreviewThumb; 94 private View mFlashOverlay; 95 96 private View mPreviewCover; 97 private SurfaceView mSurfaceView = null; 98 private int mPreviewWidth = 0; 99 private int mPreviewHeight = 0; 100 private float mSurfaceTextureUncroppedWidth; 101 private float mSurfaceTextureUncroppedHeight; 102 private float mAspectRatio = 4f / 3f; 103 private Matrix mMatrix = null; 104 private final AnimationManager mAnimationManager; 105 private final Handler mHandler = new Handler() { 106 @Override 107 public void handleMessage(Message msg) { 108 switch (msg.what) { 109 case UPDATE_TRANSFORM_MATRIX: 110 setTransformMatrix(mPreviewWidth, mPreviewHeight); 111 break; 112 default: 113 break; 114 } 115 } 116 }; 117 private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() { 118 @Override 119 public void onLayoutChange(View v, int left, int top, int right, 120 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 121 int width = right - left; 122 int height = bottom - top; 123 // Full-screen screennail 124 int w = width; 125 int h = height; 126 if (CameraUtil.getDisplayRotation(mActivity) % 180 != 0) { 127 w = height; 128 h = width; 129 } 130 if (mPreviewWidth != width || mPreviewHeight != height) { 131 mPreviewWidth = width; 132 mPreviewHeight = height; 133 onScreenSizeChanged(width, height, w, h); 134 } 135 } 136 }; 137 138 public void showPreviewCover() { 139 mPreviewCover.setVisibility(View.VISIBLE); 140 } 141 142 private class SettingsPopup extends PopupWindow { 143 public SettingsPopup(View popup) { 144 super(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 145 setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); 146 setOutsideTouchable(true); 147 setFocusable(true); 148 popup.setVisibility(View.VISIBLE); 149 setContentView(popup); 150 showAtLocation(mRootView, Gravity.CENTER, 0, 0); 151 } 152 153 public void dismiss(boolean topLevelOnly) { 154 super.dismiss(); 155 popupDismissed(); 156 showUI(); 157 mVideoMenu.popupDismissed(topLevelOnly); 158 159 // Switch back into fullscreen/lights-out mode after popup 160 // is dimissed. 161 mActivity.setSystemBarsVisibility(false); 162 } 163 164 @Override 165 public void dismiss() { 166 // Called by Framework when touch outside the popup or hit back key 167 dismiss(true); 168 } 169 } 170 171 public VideoUI(CameraActivity activity, VideoController controller, View parent) { 172 mActivity = activity; 173 mController = controller; 174 mRootView = parent; 175 mActivity.getLayoutInflater().inflate(R.layout.video_module, (ViewGroup) mRootView, true); 176 mPreviewCover = mRootView.findViewById(R.id.preview_cover); 177 mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content); 178 mTextureView.setSurfaceTextureListener(this); 179 mTextureView.addOnLayoutChangeListener(mLayoutListener); 180 mFlashOverlay = mRootView.findViewById(R.id.flash_overlay); 181 mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button); 182 mSwitcher = (ModuleSwitcher) mRootView.findViewById(R.id.camera_switcher); 183 mSwitcher.setCurrentIndex(ModuleSwitcher.VIDEO_MODULE_INDEX); 184 mSwitcher.setSwitchListener(mActivity); 185 initializeMiscControls(); 186 initializeControlByIntent(); 187 initializeOverlay(); 188 mAnimationManager = new AnimationManager(); 189 } 190 191 192 public void initializeSurfaceView() { 193 mSurfaceView = new SurfaceView(mActivity); 194 ((ViewGroup) mRootView).addView(mSurfaceView, 0); 195 mSurfaceView.getHolder().addCallback(this); 196 } 197 198 private void initializeControlByIntent() { 199 mMenuButton = mRootView.findViewById(R.id.menu); 200 mMenuButton.setOnClickListener(new OnClickListener() { 201 @Override 202 public void onClick(View v) { 203 if (mPieRenderer != null) { 204 mPieRenderer.showInCenter(); 205 } 206 } 207 }); 208 209 mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls); 210 mOnScreenIndicators = new OnScreenIndicators(mActivity, 211 mRootView.findViewById(R.id.on_screen_indicators)); 212 mOnScreenIndicators.resetToDefault(); 213 if (mController.isVideoCaptureIntent()) { 214 hideSwitcher(); 215 mActivity.getLayoutInflater().inflate(R.layout.review_module_control, 216 (ViewGroup) mCameraControls); 217 // Cannot use RotateImageView for "done" and "cancel" button because 218 // the tablet layout uses RotateLayout, which cannot be cast to 219 // RotateImageView. 220 mReviewDoneButton = mRootView.findViewById(R.id.btn_done); 221 mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel); 222 mReviewPlayButton = mRootView.findViewById(R.id.btn_play); 223 mReviewCancelButton.setVisibility(View.VISIBLE); 224 mReviewDoneButton.setOnClickListener(new OnClickListener() { 225 @Override 226 public void onClick(View v) { 227 mController.onReviewDoneClicked(v); 228 } 229 }); 230 mReviewCancelButton.setOnClickListener(new OnClickListener() { 231 @Override 232 public void onClick(View v) { 233 mController.onReviewCancelClicked(v); 234 } 235 }); 236 mReviewPlayButton.setOnClickListener(new OnClickListener() { 237 @Override 238 public void onClick(View v) { 239 mController.onReviewPlayClicked(v); 240 } 241 }); 242 } 243 } 244 245 public void setPreviewSize(int width, int height) { 246 if (width == 0 || height == 0) { 247 Log.w(TAG, "Preview size should not be 0."); 248 return; 249 } 250 if (width > height) { 251 mAspectRatio = (float) width / height; 252 } else { 253 mAspectRatio = (float) height / width; 254 } 255 mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX); 256 } 257 258 public int getPreviewWidth() { 259 return mPreviewWidth; 260 } 261 262 public int getPreviewHeight() { 263 return mPreviewHeight; 264 } 265 266 public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) { 267 setTransformMatrix(width, height); 268 } 269 270 private void setTransformMatrix(int width, int height) { 271 mMatrix = mTextureView.getTransform(mMatrix); 272 int orientation = CameraUtil.getDisplayRotation(mActivity); 273 float scaleX = 1f, scaleY = 1f; 274 float scaledTextureWidth, scaledTextureHeight; 275 if (width > height) { 276 scaledTextureWidth = Math.max(width, 277 (int) (height * mAspectRatio)); 278 scaledTextureHeight = Math.max(height, 279 (int)(width / mAspectRatio)); 280 } else { 281 scaledTextureWidth = Math.max(width, 282 (int) (height / mAspectRatio)); 283 scaledTextureHeight = Math.max(height, 284 (int) (width * mAspectRatio)); 285 } 286 287 if (mSurfaceTextureUncroppedWidth != scaledTextureWidth || 288 mSurfaceTextureUncroppedHeight != scaledTextureHeight) { 289 mSurfaceTextureUncroppedWidth = scaledTextureWidth; 290 mSurfaceTextureUncroppedHeight = scaledTextureHeight; 291 } 292 scaleX = scaledTextureWidth / width; 293 scaleY = scaledTextureHeight / height; 294 mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2); 295 mTextureView.setTransform(mMatrix); 296 297 if (mSurfaceView != null && mSurfaceView.getVisibility() == View.VISIBLE) { 298 LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams(); 299 lp.width = (int) mSurfaceTextureUncroppedWidth; 300 lp.height = (int) mSurfaceTextureUncroppedHeight; 301 lp.gravity = Gravity.CENTER; 302 mSurfaceView.requestLayout(); 303 } 304 } 305 306 /** 307 * Starts a flash animation 308 */ 309 public void animateFlash() { 310 mAnimationManager.startFlashAnimation(mFlashOverlay); 311 } 312 313 /** 314 * Starts a capture animation 315 */ 316 public void animateCapture() { 317 Bitmap bitmap = null; 318 if (mTextureView != null) { 319 bitmap = mTextureView.getBitmap((int) mSurfaceTextureUncroppedWidth / 2, 320 (int) mSurfaceTextureUncroppedHeight / 2); 321 } 322 animateCapture(bitmap); 323 } 324 325 /** 326 * Starts a capture animation 327 * @param bitmap the captured image that we shrink and slide in the animation 328 */ 329 public void animateCapture(Bitmap bitmap) { 330 if (bitmap == null) { 331 Log.e(TAG, "No valid bitmap for capture animation."); 332 return; 333 } 334 ((ImageView) mPreviewThumb).setImageBitmap(bitmap); 335 mAnimationManager.startCaptureAnimation(mPreviewThumb); 336 } 337 338 /** 339 * Cancels on-going animations 340 */ 341 public void cancelAnimations() { 342 mAnimationManager.cancelAnimations(); 343 } 344 345 public void hideUI() { 346 mCameraControls.setVisibility(View.INVISIBLE); 347 mSwitcher.closePopup(); 348 } 349 350 public void showUI() { 351 mCameraControls.setVisibility(View.VISIBLE); 352 } 353 354 public boolean arePreviewControlsVisible() { 355 return (mCameraControls.getVisibility() == View.VISIBLE); 356 } 357 358 public void hideSwitcher() { 359 mSwitcher.closePopup(); 360 mSwitcher.setVisibility(View.INVISIBLE); 361 } 362 363 public void showSwitcher() { 364 mSwitcher.setVisibility(View.VISIBLE); 365 } 366 367 public boolean collapseCameraControls() { 368 boolean ret = false; 369 if (mPopup != null) { 370 dismissPopup(false); 371 ret = true; 372 } 373 return ret; 374 } 375 376 public boolean removeTopLevelPopup() { 377 if (mPopup != null) { 378 dismissPopup(true); 379 return true; 380 } 381 return false; 382 } 383 384 public void enableCameraControls(boolean enable) { 385 if (mGestures != null) { 386 mGestures.setZoomOnly(!enable); 387 } 388 if (mPieRenderer != null && mPieRenderer.showsItems()) { 389 mPieRenderer.hide(); 390 } 391 } 392 393 public void initDisplayChangeListener() { 394 ((CameraRootView) mRootView).setDisplayChangeListener(this); 395 } 396 397 public void removeDisplayChangeListener() { 398 ((CameraRootView) mRootView).removeDisplayChangeListener(); 399 } 400 401 public void overrideSettings(final String... keyvalues) { 402 mVideoMenu.overrideSettings(keyvalues); 403 } 404 405 public void setOrientationIndicator(int orientation, boolean animation) { 406 // We change the orientation of the linearlayout only for phone UI 407 // because when in portrait the width is not enough. 408 if (mLabelsLinearLayout != null) { 409 if (((orientation / 90) & 1) == 0) { 410 mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL); 411 } else { 412 mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL); 413 } 414 } 415 mRecordingTimeRect.setOrientation(0, animation); 416 } 417 418 public SurfaceHolder getSurfaceHolder() { 419 return mSurfaceView.getHolder(); 420 } 421 422 public void hideSurfaceView() { 423 mSurfaceView.setVisibility(View.GONE); 424 mTextureView.setVisibility(View.VISIBLE); 425 setTransformMatrix(mPreviewWidth, mPreviewHeight); 426 } 427 428 public void showSurfaceView() { 429 mSurfaceView.setVisibility(View.VISIBLE); 430 mTextureView.setVisibility(View.GONE); 431 setTransformMatrix(mPreviewWidth, mPreviewHeight); 432 } 433 434 private void initializeOverlay() { 435 mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay); 436 if (mPieRenderer == null) { 437 mPieRenderer = new PieRenderer(mActivity); 438 mVideoMenu = new VideoMenu(mActivity, this, mPieRenderer); 439 mPieRenderer.setPieListener(this); 440 } 441 mRenderOverlay.addRenderer(mPieRenderer); 442 if (mZoomRenderer == null) { 443 mZoomRenderer = new ZoomRenderer(mActivity); 444 } 445 mRenderOverlay.addRenderer(mZoomRenderer); 446 if (mGestures == null) { 447 mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer); 448 mRenderOverlay.setGestures(mGestures); 449 } 450 mGestures.setRenderOverlay(mRenderOverlay); 451 452 mPreviewThumb = mRootView.findViewById(R.id.preview_thumb); 453 mPreviewThumb.setOnClickListener(new OnClickListener() { 454 @Override 455 public void onClick(View v) { 456 // Do not allow navigation to filmstrip during video recording 457 if (!mRecordingStarted) { 458 mActivity.gotoGallery(); 459 } 460 } 461 }); 462 } 463 464 public void setPrefChangedListener(OnPreferenceChangedListener listener) { 465 mVideoMenu.setListener(listener); 466 } 467 468 private void initializeMiscControls() { 469 mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image); 470 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video); 471 mShutterButton.setOnShutterButtonListener(mController); 472 mShutterButton.setVisibility(View.VISIBLE); 473 mShutterButton.requestFocus(); 474 mShutterButton.enableTouch(true); 475 mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time); 476 mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect); 477 mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label); 478 // The R.id.labels can only be found in phone layout. 479 // That is, mLabelsLinearLayout should be null in tablet layout. 480 mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels); 481 } 482 483 public void updateOnScreenIndicators(Parameters param, ComboPreferences prefs) { 484 mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode()); 485 boolean location = RecordLocationPreference.get( 486 prefs, mActivity.getContentResolver()); 487 mOnScreenIndicators.updateLocationIndicator(location); 488 489 } 490 491 public void setAspectRatio(double ratio) { 492 // mPreviewFrameLayout.setAspectRatio(ratio); 493 } 494 495 public void showTimeLapseUI(boolean enable) { 496 if (mTimeLapseLabel != null) { 497 mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE); 498 } 499 } 500 501 private void openMenu() { 502 if (mPieRenderer != null) { 503 mPieRenderer.showInCenter(); 504 } 505 } 506 507 public void dismissPopup(boolean topLevelOnly) { 508 // In review mode, we do not want to bring up the camera UI 509 if (mController.isInReviewMode()) return; 510 if (mPopup != null) { 511 mPopup.dismiss(topLevelOnly); 512 } 513 } 514 515 private void popupDismissed() { 516 mPopup = null; 517 } 518 519 public void showPopup(AbstractSettingPopup popup) { 520 hideUI(); 521 522 if (mPopup != null) { 523 mPopup.dismiss(false); 524 } 525 mPopup = new SettingsPopup(popup); 526 } 527 528 public void onShowSwitcherPopup() { 529 hidePieRenderer(); 530 } 531 532 public boolean hidePieRenderer() { 533 if (mPieRenderer != null && mPieRenderer.showsItems()) { 534 mPieRenderer.hide(); 535 return true; 536 } 537 return false; 538 } 539 540 // disable preview gestures after shutter is pressed 541 public void setShutterPressed(boolean pressed) { 542 if (mGestures == null) return; 543 mGestures.setEnabled(!pressed); 544 } 545 546 public void enableShutter(boolean enable) { 547 if (mShutterButton != null) { 548 mShutterButton.setEnabled(enable); 549 } 550 } 551 552 // PieListener 553 @Override 554 public void onPieOpened(int centerX, int centerY) { 555 setSwipingEnabled(false); 556 // Close module selection menu when pie menu is opened. 557 mSwitcher.closePopup(); 558 } 559 560 @Override 561 public void onPieClosed() { 562 setSwipingEnabled(true); 563 } 564 565 public void setSwipingEnabled(boolean enable) { 566 mActivity.setSwipingEnabled(enable); 567 } 568 569 public void showPreviewBorder(boolean enable) { 570 // TODO: mPreviewFrameLayout.showBorder(enable); 571 } 572 573 // SingleTapListener 574 // Preview area is touched. Take a picture. 575 @Override 576 public void onSingleTapUp(View view, int x, int y) { 577 mController.onSingleTapUp(view, x, y); 578 } 579 580 public void showRecordingUI(boolean recording) { 581 mRecordingStarted = recording; 582 mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE); 583 mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE); 584 if (recording) { 585 mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording); 586 hideSwitcher(); 587 mRecordingTimeView.setText(""); 588 mRecordingTimeView.setVisibility(View.VISIBLE); 589 } else { 590 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video); 591 if (!mController.isVideoCaptureIntent()) { 592 showSwitcher(); 593 } 594 mRecordingTimeView.setVisibility(View.GONE); 595 } 596 } 597 598 public void showReviewImage(Bitmap bitmap) { 599 mReviewImage.setImageBitmap(bitmap); 600 mReviewImage.setVisibility(View.VISIBLE); 601 } 602 603 public void showReviewControls() { 604 CameraUtil.fadeOut(mShutterButton); 605 CameraUtil.fadeIn(mReviewDoneButton); 606 CameraUtil.fadeIn(mReviewPlayButton); 607 mReviewImage.setVisibility(View.VISIBLE); 608 mMenuButton.setVisibility(View.GONE); 609 mOnScreenIndicators.setVisibility(View.GONE); 610 } 611 612 public void hideReviewUI() { 613 mReviewImage.setVisibility(View.GONE); 614 mShutterButton.setEnabled(true); 615 mMenuButton.setVisibility(View.VISIBLE); 616 mOnScreenIndicators.setVisibility(View.VISIBLE); 617 CameraUtil.fadeOut(mReviewDoneButton); 618 CameraUtil.fadeOut(mReviewPlayButton); 619 CameraUtil.fadeIn(mShutterButton); 620 } 621 622 private void setShowMenu(boolean show) { 623 if (mOnScreenIndicators != null) { 624 mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE); 625 } 626 if (mMenuButton != null) { 627 mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE); 628 } 629 } 630 631 public void onPreviewFocusChanged(boolean previewFocused) { 632 if (previewFocused) { 633 showUI(); 634 } else { 635 hideUI(); 636 } 637 if (mGestures != null) { 638 mGestures.setEnabled(previewFocused); 639 } 640 if (mRenderOverlay != null) { 641 // this can not happen in capture mode 642 mRenderOverlay.setVisibility(previewFocused ? View.VISIBLE : View.GONE); 643 } 644 setShowMenu(previewFocused); 645 } 646 647 public void initializePopup(PreferenceGroup pref) { 648 mVideoMenu.initialize(pref); 649 } 650 651 public void initializeZoom(Parameters param) { 652 if (param == null || !param.isZoomSupported()) { 653 mGestures.setZoomEnabled(false); 654 return; 655 } 656 mGestures.setZoomEnabled(true); 657 mZoomMax = param.getMaxZoom(); 658 mZoomRatios = param.getZoomRatios(); 659 // Currently we use immediate zoom for fast zooming to get better UX and 660 // there is no plan to take advantage of the smooth zoom. 661 mZoomRenderer.setZoomMax(mZoomMax); 662 mZoomRenderer.setZoom(param.getZoom()); 663 mZoomRenderer.setZoomValue(mZoomRatios.get(param.getZoom())); 664 mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener()); 665 } 666 667 public void clickShutter() { 668 mShutterButton.performClick(); 669 } 670 671 public void pressShutter(boolean pressed) { 672 mShutterButton.setPressed(pressed); 673 } 674 675 public View getShutterButton() { 676 return mShutterButton; 677 } 678 679 public void setRecordingTime(String text) { 680 mRecordingTimeView.setText(text); 681 } 682 683 public void setRecordingTimeTextColor(int color) { 684 mRecordingTimeView.setTextColor(color); 685 } 686 687 public boolean isVisible() { 688 return mCameraControls.getVisibility() == View.VISIBLE; 689 } 690 691 @Override 692 public void onDisplayChanged() { 693 mCameraControls.checkLayoutFlip(); 694 mController.updateCameraOrientation(); 695 } 696 697 private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener { 698 @Override 699 public void onZoomValueChanged(int index) { 700 int newZoom = mController.onZoomChanged(index); 701 if (mZoomRenderer != null) { 702 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom)); 703 } 704 } 705 706 @Override 707 public void onZoomStart() { 708 } 709 710 @Override 711 public void onZoomEnd() { 712 } 713 } 714 715 public SurfaceTexture getSurfaceTexture() { 716 return mSurfaceTexture; 717 } 718 719 // SurfaceTexture callbacks 720 @Override 721 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 722 mSurfaceTexture = surface; 723 mController.onPreviewUIReady(); 724 } 725 726 @Override 727 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 728 mSurfaceTexture = null; 729 mController.onPreviewUIDestroyed(); 730 Log.d(TAG, "surfaceTexture is destroyed"); 731 return true; 732 } 733 734 @Override 735 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 736 } 737 738 @Override 739 public void onSurfaceTextureUpdated(SurfaceTexture surface) { 740 // Make sure preview cover is hidden if preview data is available. 741 if (mPreviewCover.getVisibility() != View.GONE) { 742 mPreviewCover.setVisibility(View.GONE); 743 } 744 } 745 746 // SurfaceHolder callbacks 747 @Override 748 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 749 Log.v(TAG, "Surface changed. width=" + width + ". height=" + height); 750 } 751 752 @Override 753 public void surfaceCreated(SurfaceHolder holder) { 754 Log.v(TAG, "Surface created"); 755 } 756 757 @Override 758 public void surfaceDestroyed(SurfaceHolder holder) { 759 Log.v(TAG, "Surface destroyed"); 760 mController.stopPreview(); 761 } 762 } 763