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