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