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