Home | History | Annotate | Download | only in camera
      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