1f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu/*
2f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * Copyright (C) 2013 The Android Open Source Project
3f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu *
4f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * Licensed under the Apache License, Version 2.0 (the "License");
5f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * you may not use this file except in compliance with the License.
6f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * You may obtain a copy of the License at
7f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu *
8f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu *      http://www.apache.org/licenses/LICENSE-2.0
9f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu *
10f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * Unless required by applicable law or agreed to in writing, software
11f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * distributed under the License is distributed on an "AS IS" BASIS,
12f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * See the License for the specific language governing permissions and
14f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * limitations under the License.
15f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu */
16f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
17f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liupackage com.android.camera.app;
18f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
1928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liuimport android.content.res.Resources;
20213a4a086b54904cee543adf60b16fc1a61efe38Doris Liuimport android.graphics.Bitmap;
21213a4a086b54904cee543adf60b16fc1a61efe38Doris Liuimport android.graphics.Canvas;
22f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport android.graphics.Matrix;
23213a4a086b54904cee543adf60b16fc1a61efe38Doris Liuimport android.graphics.RectF;
2406db742814dd635d100639f977fcfdc904deb778Doris Liuimport android.graphics.SurfaceTexture;
2511ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liuimport android.hardware.display.DisplayManager;
265052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.util.CameraPerformanceTracker;
27f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport android.view.GestureDetector;
28f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport android.view.LayoutInflater;
29f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport android.view.MotionEvent;
30f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport android.view.TextureView;
31f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport android.view.View;
32f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport android.view.ViewConfiguration;
33e0aff89f3e05eb6008651b290ba79d484de55970Angus Kongimport android.view.ViewGroup;
34c6c9740d996bf073a157721aa3eb2a1aa60c477dDoris Liuimport android.widget.FrameLayout;
3564d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberlingimport android.widget.ImageButton;
36f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
37971ad50c0f220a396ffce50245617ff59ed0a09ezafirimport com.android.camera.AccessibilityUtil;
38f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport com.android.camera.AnimationManager;
39b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgrenimport com.android.camera.ButtonManager;
4028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liuimport com.android.camera.CaptureLayoutHelper;
41b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgrenimport com.android.camera.ShutterButton;
42e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberlingimport com.android.camera.TextureViewHelper;
435596b4c902dcb685928b43678f428746ca5ffd08Angus Kongimport com.android.camera.debug.Log;
44b2510252fb020f3ccb88787c870930427377b9dfAngus Kongimport com.android.camera.filmstrip.FilmstripContentPanel;
45b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgrenimport com.android.camera.hardware.HardwareSpec;
46b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgrenimport com.android.camera.module.ModuleController;
476190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgrenimport com.android.camera.settings.Keys;
48b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgrenimport com.android.camera.settings.SettingsManager;
49c813ce181810a444b6fea4a399e6685aef4103e2Sascha Haeberlingimport com.android.camera.ui.AbstractTutorialOverlay;
500f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Spragueimport com.android.camera.ui.BottomBar;
511dfe7828fd60741b9752553af3ee439c04e758a0Doris Liuimport com.android.camera.ui.CaptureAnimationOverlay;
52b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgrenimport com.android.camera.ui.GridLines;
53f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport com.android.camera.ui.MainActivityLayout;
54f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport com.android.camera.ui.ModeListView;
55f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport com.android.camera.ui.ModeTransitionView;
56f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport com.android.camera.ui.PreviewOverlay;
5706db742814dd635d100639f977fcfdc904deb778Doris Liuimport com.android.camera.ui.PreviewStatusListener;
58427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Huimport com.android.camera.ui.StickyBottomCaptureLayout;
59b7c7d9a067cd52a27cfbaf0714a2074f972d836dAndy Huibersimport com.android.camera.ui.TouchCoordinate;
60987ee64612e2510004fdf08536746c87234d01c1Paul Rohdeimport com.android.camera.ui.focus.FocusRing;
618be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohdeimport com.android.camera.util.AndroidServices;
6211ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liuimport com.android.camera.util.ApiHelper;
6311ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liuimport com.android.camera.util.CameraUtil;
649d264309a341c52601bdccdeff6647e0ce58c31fDoris Liuimport com.android.camera.util.Gusterpolator;
65d706ea69a87229dca5cb8f16125decfbcbc5303dErin Dahlgrenimport com.android.camera.util.PhotoSphereHelper;
66e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liuimport com.android.camera.widget.Cling;
67ab05a742fb03b2016d2792c7b06f268d3dd82701Sascha Haeberlingimport com.android.camera.widget.FilmstripLayout;
688793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberlingimport com.android.camera.widget.IndicatorIconController;
69165bb8d85e6eab4e261c6b21a754ee227f732795Erin Dahlgrenimport com.android.camera.widget.ModeOptionsOverlay;
70427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Huimport com.android.camera.widget.RoundedThumbnailView;
71f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport com.android.camera2.R;
72772951602f9cfccd097283e3b78d188838c82138Erin Dahlgren
73f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu/**
74f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * CameraAppUI centralizes control of views shared across modules. Whereas module
75f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * specific views will be handled in each Module UI. For example, we can now
76f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * bring the flash animation and capture animation up from each module to app
77f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * level, as these animations are largely the same for all modules.
78f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu *
79f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * This class also serves to disambiguate touch events. It recognizes all the
80f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * swipe gestures that happen on the preview by attaching a touch listener to
81f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * a full-screen view on top of preview TextureView. Since CameraAppUI has knowledge
82f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * of how swipe from each direction should be handled, it can then redirect these
83f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu * events to appropriate recipient views.
84f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu */
8506db742814dd635d100639f977fcfdc904deb778Doris Liupublic class CameraAppUI implements ModeListView.ModeSwitchListener,
863c62221afd869828ba867fce15755a582f2c2334Erin Dahlgren                                    TextureView.SurfaceTextureListener,
873c62221afd869828ba867fce15755a582f2c2334Erin Dahlgren                                    ModeListView.ModeListOpenListener,
88a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren                                    SettingsManager.OnSettingChangedListener,
89a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren                                    ShutterButton.OnShutterButtonListener {
90e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
91e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong    /**
92e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong     * The bottom controls on the filmstrip.
93e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong     */
947ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong    public static interface BottomPanel {
95e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        /** Values for the view state of the button. */
9600b3371ca5c3340a81174ea5443443a9176d5130Angus Kong        public final int VIEWER_NONE = 0;
9700b3371ca5c3340a81174ea5443443a9176d5130Angus Kong        public final int VIEWER_PHOTO_SPHERE = 1;
9800b3371ca5c3340a81174ea5443443a9176d5130Angus Kong        public final int VIEWER_REFOCUS = 2;
9900b3371ca5c3340a81174ea5443443a9176d5130Angus Kong        public final int VIEWER_OTHER = 3;
100e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
101e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        /**
102e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         * Sets a new or replaces an existing listener for bottom control events.
103e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         */
104e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        void setListener(Listener listener);
105e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
106e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        /**
107e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu         * Sets cling for external viewer button.
108e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu         */
109e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        void setClingForViewer(int viewerType, Cling cling);
110e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
111e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        /**
112e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu         * Clears cling for external viewer button.
113e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu         */
114e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        void clearClingForViewer(int viewerType);
115e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
116e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        /**
117e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu         * Returns a cling for the specified viewer type.
118e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu         */
119e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        Cling getClingForViewer(int viewerType);
120e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
121e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        /**
122e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         * Set if the bottom controls are visible.
123e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         * @param visible {@code true} if visible.
124e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         */
125e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        void setVisible(boolean visible);
126e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
127e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        /**
128e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         * @param visible Whether the button is visible.
129e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         */
130e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        void setEditButtonVisibility(boolean visible);
131e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
132e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        /**
133e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong         * @param enabled Whether the button is enabled.
134e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong         */
135e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong        void setEditEnabled(boolean enabled);
136e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong
137e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong        /**
138e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         * Sets the visibility of the view-photosphere button.
139e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         *
14000b3371ca5c3340a81174ea5443443a9176d5130Angus Kong         * @param state one of {@link #VIEWER_NONE}, {@link #VIEWER_PHOTO_SPHERE},
14100b3371ca5c3340a81174ea5443443a9176d5130Angus Kong         *            {@link #VIEWER_REFOCUS}.
142e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         */
14300b3371ca5c3340a81174ea5443443a9176d5130Angus Kong        void setViewerButtonVisibility(int state);
144e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
145e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        /**
146e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong         * @param enabled Whether the button is enabled.
147e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong         */
148e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong        void setViewEnabled(boolean enabled);
149e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong
150e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong        /**
151e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong         * @param enabled Whether the button is enabled.
152e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong         */
153e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong        void setTinyPlanetEnabled(boolean enabled);
154e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong
155e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong        /**
156e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         * @param visible Whether the button is visible.
157e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         */
158e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        void setDeleteButtonVisibility(boolean visible);
159e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
160e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        /**
161e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong         * @param enabled Whether the button is enabled.
162e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong         */
163e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong        void setDeleteEnabled(boolean enabled);
164e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong
165e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong        /**
166e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         * @param visible Whether the button is visible.
167e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         */
168e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        void setShareButtonVisibility(boolean visible);
169e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
170e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        /**
171e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong         * @param enabled Whether the button is enabled.
172e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong         */
173e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong        void setShareEnabled(boolean enabled);
174e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong
175e4002f3a703a1835dce30d74ccfc22e00956e13fAngus Kong        /**
1767ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong         * Sets the texts for progress UI.
1777ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong         *
1787ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong         * @param text The text to show.
1797ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong         */
1807ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong        void setProgressText(CharSequence text);
1817ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong
1827ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong        /**
1837ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong         * Sets the progress.
1847ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong         *
1857ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong         * @param progress The progress value. Should be between 0 and 100.
1867ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong         */
1877ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong        void setProgress(int progress);
1887ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong
1897ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong        /**
190597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling         * Replaces the progress UI with an error message.
191597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling         */
192597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling        void showProgressError(CharSequence message);
193597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling
194597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling        /**
195597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling         * Hide the progress error message.
196597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling         */
197597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling        void hideProgressError();
198597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling
199597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling        /**
200001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong         * Shows the progress.
2017ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong         */
2027ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong        void showProgress();
2037ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong
2047ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong        /**
205001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong         * Hides the progress.
206001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong         */
207001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong        void hideProgress();
208001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong
209001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong        /**
210001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong         * Shows the controls.
2117ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong         */
2127ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong        void showControls();
2137ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong
2147ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong        /**
215001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong         * Hides the controls.
216001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong         */
217001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong        void hideControls();
218001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong
219001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong        /**
220e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         * Classes implementing this interface can listen for events on the bottom
221e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         * controls.
222e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong         */
223e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        public static interface Listener {
224e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong            /**
225e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong             * Called when the user pressed the "view" button to e.g. view a photo
226e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong             * sphere or RGBZ image.
227e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong             */
2288a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong            public void onExternalViewer();
229e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
230e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong            /**
231e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong             * Called when the "edit" button is pressed.
232e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong             */
233e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong            public void onEdit();
234e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
235e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong            /**
236e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong             * Called when the "tiny planet" button is pressed.
237e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong             */
238e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong            public void onTinyPlanet();
239e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
240e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong            /**
241e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong             * Called when the "delete" button is pressed.
242e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong             */
243e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong            public void onDelete();
244e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
245e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong            /**
246e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong             * Called when the "share" button is pressed.
247e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong             */
248e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong            public void onShare();
249597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling
250597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling            /**
251597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling             * Called when the progress error message is clicked.
252597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling             */
253597c1a093f840af3c42e00af05da01ef124dc846Sascha Haeberling            public void onProgressErrorClicked();
254e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        }
255e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong    }
256e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong
257b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren    /**
258b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * BottomBarUISpec provides a structure for modules
259b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * to specify their ideal bottom bar mode options layout.
260b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     *
261b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * Once constructed by a module, this class should be
262b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * treated as read only.
263b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     *
264b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * The application then edits this spec according to
265b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * hardware limitations and displays the final bottom
266b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * bar ui.
267b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     */
268b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren    public static class BottomBarUISpec {
269b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /** Mode options UI */
270b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
271b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
272b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * Set true if the camera option should be enabled.
273b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * If not set or false, and multiple cameras are supported,
274b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * the camera option will be disabled.
275b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         *
276b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * If multiple cameras are not supported, this preference
277b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * is ignored and the camera option will not be visible.
278b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
279b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public boolean enableCamera;
280b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
281b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
282a9ceaf76b72cb4b499d3d9d90f979bae93bd593dErin Dahlgren         * Set true if the camera option should not be visible, regardless
283a9ceaf76b72cb4b499d3d9d90f979bae93bd593dErin Dahlgren         * of hardware limitations.
284a9ceaf76b72cb4b499d3d9d90f979bae93bd593dErin Dahlgren         */
285a9ceaf76b72cb4b499d3d9d90f979bae93bd593dErin Dahlgren        public boolean hideCamera;
286a9ceaf76b72cb4b499d3d9d90f979bae93bd593dErin Dahlgren
287a9ceaf76b72cb4b499d3d9d90f979bae93bd593dErin Dahlgren        /**
288b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * Set true if the photo flash option should be enabled.
289b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * If not set or false, the photo flash option will be
290b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * disabled.
291b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         *
292b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * If the hardware does not support multiple flash values,
293b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * this preference is ignored and the flash option will
294b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * be disabled.  It will not be made invisible in order to
295b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * preserve a consistent experience across devices and between
296b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * front and back cameras.
297b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
298b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public boolean enableFlash;
299b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
300b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
301b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * Set true if the video flash option should be enabled.
302b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * Same disable rules apply as the photo flash option.
303b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
304b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public boolean enableTorchFlash;
305b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
306b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
30715473d4b69f4ad619aa10430e4bc86ab4fa815d0Erin Dahlgren         * Set true if the HDR+ flash option should be enabled.
30815473d4b69f4ad619aa10430e4bc86ab4fa815d0Erin Dahlgren         * Same disable rules apply as the photo flash option.
30915473d4b69f4ad619aa10430e4bc86ab4fa815d0Erin Dahlgren         */
31015473d4b69f4ad619aa10430e4bc86ab4fa815d0Erin Dahlgren        public boolean enableHdrPlusFlash;
31115473d4b69f4ad619aa10430e4bc86ab4fa815d0Erin Dahlgren
31215473d4b69f4ad619aa10430e4bc86ab4fa815d0Erin Dahlgren        /**
313d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren         * Set true if flash should not be visible, regardless of
314d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren         * hardware limitations.
315d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren         */
316d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        public boolean hideFlash;
317d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren
318d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        /**
319b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * Set true if the hdr/hdr+ option should be enabled.
320b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * If not set or false, the hdr/hdr+ option will be disabled.
321b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         *
322b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * Hdr or hdr+ will be chosen based on hardware limitations,
323b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * with hdr+ prefered.
324b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         *
325b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * If hardware supports neither hdr nor hdr+, then the hdr/hdr+
326b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * will not be visible.
327b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
328b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public boolean enableHdr;
329b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
330b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
331d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren         * Set true if hdr/hdr+ should not be visible, regardless of
332b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * hardware limitations.
333b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
334d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        public boolean hideHdr;
335b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
336b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
337d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren         * Set true if grid lines should be visible.  Not setting this
338d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren         * causes grid lines to be disabled.  This option is agnostic to
339d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren         * the hardware.
340b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
341d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        public boolean enableGridLines;
342d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren
343d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        /**
344d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren         * Set true if grid lines should not be visible.
345d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren         */
346d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        public boolean hideGridLines;
347b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
348a1fab413bcbe5f62ae1d829bac0539519fef96a6Erin Dahlgren        /**
349f80ac9ee5c66671c3a77ac6628fefc86cd39d57eErin Dahlgren         * Set true if the panorama orientation option should be visible.
350a1fab413bcbe5f62ae1d829bac0539519fef96a6Erin Dahlgren         *
351a1fab413bcbe5f62ae1d829bac0539519fef96a6Erin Dahlgren         * This option is not constrained by hardware limitations.
352a1fab413bcbe5f62ae1d829bac0539519fef96a6Erin Dahlgren         */
353f80ac9ee5c66671c3a77ac6628fefc86cd39d57eErin Dahlgren        public boolean enablePanoOrientation;
354a1fab413bcbe5f62ae1d829bac0539519fef96a6Erin Dahlgren
35557c889d4b88517dd0996547dbae4f314c2a3fcdfzafir        /**
35657c889d4b88517dd0996547dbae4f314c2a3fcdfzafir         * Set true if manual exposure compensation should be visible.
35757c889d4b88517dd0996547dbae4f314c2a3fcdfzafir         *
35857c889d4b88517dd0996547dbae4f314c2a3fcdfzafir         * This option is not constrained by hardware limitations.
35957c889d4b88517dd0996547dbae4f314c2a3fcdfzafir         * For example, this is false in HDR+ mode.
36057c889d4b88517dd0996547dbae4f314c2a3fcdfzafir         */
361abf54e2994961395a0feb0b08353e62718443f23Spike Sprague        public boolean enableExposureCompensation;
362abf54e2994961395a0feb0b08353e62718443f23Spike Sprague
36357c889d4b88517dd0996547dbae4f314c2a3fcdfzafir        /**
3646ffdeac1670c8938d0331c89d9269b68f361d6fazafir         * Set true if the device and module support exposure compensation.
3656ffdeac1670c8938d0331c89d9269b68f361d6fazafir         * Used only to show exposure button in disabled (greyed out) state.
36657c889d4b88517dd0996547dbae4f314c2a3fcdfzafir         */
36757c889d4b88517dd0996547dbae4f314c2a3fcdfzafir        public boolean isExposureCompensationSupported;
36857c889d4b88517dd0996547dbae4f314c2a3fcdfzafir
369b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /** Intent UI */
370b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
371b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
372b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * Set true if the intent ui cancel option should be visible.
373b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
374b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public boolean showCancel;
375b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
376b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * Set true if the intent ui done option should be visible.
377b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
378b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public boolean showDone;
379b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
380b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * Set true if the intent ui retake option should be visible.
381b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
382b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public boolean showRetake;
383b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
384b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * Set true if the intent ui review option should be visible.
385b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
386b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public boolean showReview;
387b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
388b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /** Mode options callbacks */
389b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
390b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
391f80ac9ee5c66671c3a77ac6628fefc86cd39d57eErin Dahlgren         * A {@link com.android.camera.ButtonManager.ButtonCallback}
392b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * that will be executed when the camera option is pressed. This
393b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * callback can be null.
394b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
395b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public ButtonManager.ButtonCallback cameraCallback;
396b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
397b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
398f80ac9ee5c66671c3a77ac6628fefc86cd39d57eErin Dahlgren         * A {@link com.android.camera.ButtonManager.ButtonCallback}
399b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * that will be executed when the flash option is pressed. This
400b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * callback can be null.
401b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
402b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public ButtonManager.ButtonCallback flashCallback;
403b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
404b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
405f80ac9ee5c66671c3a77ac6628fefc86cd39d57eErin Dahlgren         * A {@link com.android.camera.ButtonManager.ButtonCallback}
406b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * that will be executed when the hdr/hdr+ option is pressed. This
407b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * callback can be null.
408b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
409b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public ButtonManager.ButtonCallback hdrCallback;
410b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
411b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
412f80ac9ee5c66671c3a77ac6628fefc86cd39d57eErin Dahlgren         * A {@link com.android.camera.ButtonManager.ButtonCallback}
413d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren         * that will be executed when the grid lines option is pressed. This
414b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * callback can be null.
415b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
416d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        public ButtonManager.ButtonCallback gridLinesCallback;
417b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
418a1fab413bcbe5f62ae1d829bac0539519fef96a6Erin Dahlgren        /**
419f80ac9ee5c66671c3a77ac6628fefc86cd39d57eErin Dahlgren         * A {@link com.android.camera.ButtonManager.ButtonCallback}
420f80ac9ee5c66671c3a77ac6628fefc86cd39d57eErin Dahlgren         * that will execute when the panorama orientation option is pressed.
421a1fab413bcbe5f62ae1d829bac0539519fef96a6Erin Dahlgren         * This callback can be null.
422a1fab413bcbe5f62ae1d829bac0539519fef96a6Erin Dahlgren         */
423f80ac9ee5c66671c3a77ac6628fefc86cd39d57eErin Dahlgren        public ButtonManager.ButtonCallback panoOrientationCallback;
424a1fab413bcbe5f62ae1d829bac0539519fef96a6Erin Dahlgren
425b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /** Intent UI callbacks */
426b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
427b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
428b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * A {@link android.view.View.OnClickListener} that will execute
429b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * when the cancel option is pressed. This callback can be null.
430b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
431b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public View.OnClickListener cancelCallback;
432b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
433b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
434b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * A {@link android.view.View.OnClickListener} that will execute
435b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * when the done option is pressed. This callback can be null.
436b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
437b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public View.OnClickListener doneCallback;
438b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
439b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
440b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * A {@link android.view.View.OnClickListener} that will execute
441b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * when the retake option is pressed. This callback can be null.
442b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
443b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public View.OnClickListener retakeCallback;
444b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
445b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /**
446b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * A {@link android.view.View.OnClickListener} that will execute
447b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         * when the review option is pressed. This callback can be null.
448b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren         */
449b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        public View.OnClickListener reviewCallback;
450abf54e2994961395a0feb0b08353e62718443f23Spike Sprague
451abf54e2994961395a0feb0b08353e62718443f23Spike Sprague        /**
452abf54e2994961395a0feb0b08353e62718443f23Spike Sprague         * A ExposureCompensationSetCallback that will execute
453abf54e2994961395a0feb0b08353e62718443f23Spike Sprague         * when an expsosure button is pressed. This callback can be null.
454abf54e2994961395a0feb0b08353e62718443f23Spike Sprague         */
455abf54e2994961395a0feb0b08353e62718443f23Spike Sprague        public interface ExposureCompensationSetCallback {
456a479fcaad5b83c8fbb881f491d93145531b25cbaSpike Sprague            public void setExposure(int value);
457abf54e2994961395a0feb0b08353e62718443f23Spike Sprague        }
458abf54e2994961395a0feb0b08353e62718443f23Spike Sprague        public ExposureCompensationSetCallback exposureCompensationSetCallback;
459a479fcaad5b83c8fbb881f491d93145531b25cbaSpike Sprague
460a479fcaad5b83c8fbb881f491d93145531b25cbaSpike Sprague        /**
461a479fcaad5b83c8fbb881f491d93145531b25cbaSpike Sprague         * Exposure compensation parameters.
462a479fcaad5b83c8fbb881f491d93145531b25cbaSpike Sprague         */
463a479fcaad5b83c8fbb881f491d93145531b25cbaSpike Sprague        public int minExposureCompensation;
464a479fcaad5b83c8fbb881f491d93145531b25cbaSpike Sprague        public int maxExposureCompensation;
465a479fcaad5b83c8fbb881f491d93145531b25cbaSpike Sprague        public float exposureCompensationStep;
4666c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
4676c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        /**
4684333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling         * Whether self-timer is enabled.
4696c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu         */
4706c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        public boolean enableSelfTimer = false;
4714333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling
4724333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling        /**
4734333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling         * Whether the option for self-timer should show. If true and
4744333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling         * {@link #enableSelfTimer} is false, then the option should be shown
4754333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling         * disabled.
4764333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling         */
4774333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling        public boolean showSelfTimer = false;
478b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren    }
479b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
480b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
4815596b4c902dcb685928b43678f428746ca5ffd08Angus Kong    private final static Log.Tag TAG = new Log.Tag("CameraAppUI");
482f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
483f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private final AppController mController;
484f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private final boolean mIsCaptureIntent;
485f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private final AnimationManager mAnimationManager;
486f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
487f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    // Swipe states:
4882b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private final static int IDLE = 0;
4892b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private final static int SWIPE_UP = 1;
4902b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private final static int SWIPE_DOWN = 2;
4912b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private final static int SWIPE_LEFT = 3;
4922b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private final static int SWIPE_RIGHT = 4;
4938793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling    private boolean mSwipeEnabled = true;
494f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
495d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    // Shared Surface Texture properities.
496d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    private SurfaceTexture mSurface;
497d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    private int mSurfaceWidth;
498d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    private int mSurfaceHeight;
499d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
500f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    // Touch related measures:
501f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private final int mSlop;
5022b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private final static int SWIPE_TIME_OUT_MS = 500;
5032b906b8c9754b564d5113c7a342654c82f97f180Doris Liu
5042b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    // Mode cover states:
5052b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private final static int COVER_HIDDEN = 0;
5062b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private final static int COVER_SHOWN = 1;
5072b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private final static int COVER_WILL_HIDE_AT_NEXT_FRAME = 2;
5087e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin    private final static int COVER_WILL_HIDE_AFTER_NEXT_TEXTURE_UPDATE = 3;
5097e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin    private final static int COVER_WILL_HIDE_AT_NEXT_TEXTURE_UPDATE = 4;
510f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
5116809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu    /**
5126809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu     * Preview down-sample rate when taking a screenshot.
5136809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu     */
5146809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu    private final static int DOWN_SAMPLE_RATE_FOR_SCREENSHOT = 2;
5156809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu
516f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    // App level views:
517b41034b16b0dce997544d2592db5029e7db4e238Doris Liu    private final FrameLayout mCameraRootView;
518f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private final ModeTransitionView mModeTransitionView;
519f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private final MainActivityLayout mAppRootView;
520f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private final ModeListView mModeListView;
521166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong    private final FilmstripLayout mFilmstripLayout;
522f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private TextureView mTextureView;
523c6c9740d996bf073a157721aa3eb2a1aa60c477dDoris Liu    private FrameLayout mModuleUI;
5245d18769f53db81d401488811250570290a73626bErin Dahlgren    private ShutterButton mShutterButton;
52564d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling    private ImageButton mCountdownCancelButton;
52670da918464276b110c43868caa272c97baadb89eDoris Liu    private BottomBar mBottomBar;
527165bb8d85e6eab4e261c6b21a754ee227f732795Erin Dahlgren    private ModeOptionsOverlay mModeOptionsOverlay;
528e2a1f54fbf6a8a7beff5b7695654ca21e63643afErin Dahlgren    private IndicatorIconController mIndicatorIconController;
529987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    private FocusRing mFocusRing;
5301e0810c88e791d0f658eb5a6f95d771ee03a7631Sascha Haeberling    private FrameLayout mTutorialsPlaceHolderWrapper;
531427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    private StickyBottomCaptureLayout mStickyBottomCaptureLayout;
53270da918464276b110c43868caa272c97baadb89eDoris Liu    private TextureViewHelper mTextureViewHelper;
533ab05a742fb03b2016d2792c7b06f268d3dd82701Sascha Haeberling    private final GestureDetector mGestureDetector;
53411ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    private DisplayManager.DisplayListener mDisplayListener;
53511ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    private int mLastRotation;
536f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private int mSwipeState = IDLE;
537f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu    private PreviewOverlay mPreviewOverlay;
538b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren    private GridLines mGridLines;
5391dfe7828fd60741b9752553af3ee439c04e758a0Doris Liu    private CaptureAnimationOverlay mCaptureOverlay;
54006db742814dd635d100639f977fcfdc904deb778Doris Liu    private PreviewStatusListener mPreviewStatusListener;
5412b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private int mModeCoverState = COVER_HIDDEN;
5427ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong    private final FilmstripBottomPanel mFilmstripBottomControls;
543ab05a742fb03b2016d2792c7b06f268d3dd82701Sascha Haeberling    private final FilmstripContentPanel mFilmstripPanel;
544b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu    private Runnable mHideCoverRunnable;
5454a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    private final View.OnLayoutChangeListener mPreviewLayoutChangeListener
5464a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            = new View.OnLayoutChangeListener() {
5474a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        @Override
5484a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
5494a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu                int oldTop, int oldRight, int oldBottom) {
5504a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            if (mPreviewStatusListener != null) {
5514a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu                mPreviewStatusListener.onPreviewLayoutChanged(v, left, top, right, bottom, oldLeft,
5524a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu                        oldTop, oldRight, oldBottom);
5534a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            }
5544a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        }
5554a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    };
5569d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    private View mModeOptionsToggle;
557427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    private final RoundedThumbnailView mRoundedThumbnailView;
55828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu    private final CaptureLayoutHelper mCaptureLayoutHelper;
559256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling    private final View mAccessibilityAffordances;
560971ad50c0f220a396ffce50245617ff59ed0a09ezafir    private AccessibilityUtil mAccessibilityUtil;
561f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
562d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague    private boolean mDisableAllUserInteractions;
563ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu    /** Whether to prevent capture indicator from being triggered. */
564ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu    private boolean mSuppressCaptureIndicator;
565ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu
5664368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava    /** Supported HDR mode (none, hdr, hdr+). */
5674368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava    private String mHdrSupportMode;
568ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava
569ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava    /** Used to track the last scope used to update the bottom bar UI. */
570ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava    private String mCurrentCameraScope;
571ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava    private String mCurrentModuleScope;
572ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava
573213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu    /**
574213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu     * Provides current preview frame and the controls/overlay from the module that
575213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu     * are shown on top of the preview.
576213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu     */
577213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu    public interface CameraModuleScreenShotProvider {
578213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu        /**
579213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         * Returns the current preview frame down-sampled using the given down-sample
580213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         * factor.
581213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         *
582213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         * @param downSampleFactor the down sample factor for down sampling the
583213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         *                         preview frame. (e.g. a down sample factor of
584213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         *                         2 means to scale down the preview frame to 1/2
585213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         *                         the width and height.)
586213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         * @return down-sampled preview frame
587213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         */
588213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu        public Bitmap getPreviewFrame(int downSampleFactor);
589213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu
590213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu        /**
591213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         * @return the controls and overlays that are currently showing on top of
592213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         *         the preview drawn into a bitmap with no scaling applied.
593213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu         */
594213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu        public Bitmap getPreviewOverlayAndControls();
5956809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu
5966809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu        /**
5976809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu         * Returns a bitmap containing the current screenshot.
5986809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu         *
5996809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu         * @param previewDownSampleFactor the downsample factor applied on the
6006809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu         *                                preview frame when taking the screenshot
6016809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu         */
6026809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu        public Bitmap getScreenShot(int previewDownSampleFactor);
603213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu    }
604213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu
6059d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    /**
60628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu     * This listener gets called when the size of the window (excluding the system
60728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu     * decor such as status bar and nav bar) has changed.
6089d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu     */
60928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu    public interface NonDecorWindowSizeChangedListener {
610344320c90639f823451ddac42e8f39b74727787cDoris Liu        public void onNonDecorWindowSizeChanged(int width, int height, int rotation);
6119d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    }
6129d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu
613213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu    private final CameraModuleScreenShotProvider mCameraModuleScreenShotProvider =
614213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu            new CameraModuleScreenShotProvider() {
615213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                @Override
616213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                public Bitmap getPreviewFrame(int downSampleFactor) {
617213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                    if (mCameraRootView == null || mTextureView == null) {
618213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                        return null;
619213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                    }
620213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                    // Gets the bitmap from the preview TextureView.
621274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael                    Bitmap preview = mTextureViewHelper.getPreviewBitmap(downSampleFactor);
622213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                    return preview;
623213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                }
624213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu
625213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                @Override
626213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                public Bitmap getPreviewOverlayAndControls() {
627213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                    Bitmap overlays = Bitmap.createBitmap(mCameraRootView.getWidth(),
628213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                            mCameraRootView.getHeight(), Bitmap.Config.ARGB_8888);
629213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                    Canvas canvas = new Canvas(overlays);
630213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                    mCameraRootView.draw(canvas);
631213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                    return overlays;
632213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu                }
6336809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu
6346809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                @Override
6356809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                public Bitmap getScreenShot(int previewDownSampleFactor) {
6366809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                    Bitmap screenshot = Bitmap.createBitmap(mCameraRootView.getWidth(),
6376809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                            mCameraRootView.getHeight(), Bitmap.Config.ARGB_8888);
6386809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                    Canvas canvas = new Canvas(screenshot);
6396809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                    canvas.drawARGB(255, 0, 0, 0);
640274f6e962e9e7f94cfc4ceb9cad3fa8dc0a80abbSeth Raphael                    Bitmap preview = mTextureViewHelper.getPreviewBitmap(previewDownSampleFactor);
6416809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                    if (preview != null) {
6426809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                        canvas.drawBitmap(preview, null, mTextureViewHelper.getPreviewArea(), null);
6436809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                    }
6446809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                    Bitmap overlay = getPreviewOverlayAndControls();
6456809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                    if (overlay != null) {
6466809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                        canvas.drawBitmap(overlay, 0f, 0f, null);
6476809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                    }
6486809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                    return screenshot;
6496809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                }
650213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu            };
651213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu
652a0e8347f9cfb583f90543635c5c86dc9252526e1Kevin Gabayan    private long mCoverHiddenTime = -1; // System time when preview cover was hidden.
653a0e8347f9cfb583f90543635c5c86dc9252526e1Kevin Gabayan
654a0e8347f9cfb583f90543635c5c86dc9252526e1Kevin Gabayan    public long getCoverHiddenTime() {
655a0e8347f9cfb583f90543635c5c86dc9252526e1Kevin Gabayan        return mCoverHiddenTime;
656a0e8347f9cfb583f90543635c5c86dc9252526e1Kevin Gabayan    }
657a0e8347f9cfb583f90543635c5c86dc9252526e1Kevin Gabayan
658d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /**
659d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * This resets the preview to have no applied transform matrix.
660d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     */
661d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public void clearPreviewTransform() {
662d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mTextureViewHelper.clearTransform();
663d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
664d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
66570da918464276b110c43868caa272c97baadb89eDoris Liu    public void updatePreviewAspectRatio(float aspectRatio) {
66670da918464276b110c43868caa272c97baadb89eDoris Liu        mTextureViewHelper.updateAspectRatio(aspectRatio);
6670f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague    }
6680f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague
6697bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk    /**
6707bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk     * WAR: Reset the SurfaceTexture's default buffer size to the current view dimensions of
6717bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk     * its TextureView.  This is necessary to get the expected behavior for the TextureView's
6727bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk     * HardwareLayer transform matrix (set by TextureView#setTransform) after configuring the
6737bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk     * SurfaceTexture as an output for the Camera2 API (which involves changing the default buffer
6747bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk     * size).
6757bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk     *
6767bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk     * b/17286155 - Tracking a fix for this in HardwareLayer.
6777bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk     */
6787bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk    public void setDefaultBufferSizeToViewDimens() {
6797bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk        if (mSurface == null || mTextureView == null) {
6807bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk            Log.w(TAG, "Could not set SurfaceTexture default buffer dimensions, not yet setup");
6817bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk            return;
6827bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk        }
6837bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk        mSurface.setDefaultBufferSize(mTextureView.getWidth(), mTextureView.getHeight());
6847bae31a17a7913b58b96787185cd965baef97f76Ruben Brunk    }
68502c129a598b6a165885fe950275675d62993d2eeSeth Raphael
68602c129a598b6a165885fe950275675d62993d2eeSeth Raphael    /**
6876382c70a769b9ec94a3b0372ee27c0cd075e8be8Seth Raphael     * Updates the preview matrix without altering it.
688159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague     *
68902c129a598b6a165885fe950275675d62993d2eeSeth Raphael     * @param matrix
6906382c70a769b9ec94a3b0372ee27c0cd075e8be8Seth Raphael     * @param aspectRatio the desired aspect ratio for the preview.
69102c129a598b6a165885fe950275675d62993d2eeSeth Raphael     */
6926382c70a769b9ec94a3b0372ee27c0cd075e8be8Seth Raphael    public void updatePreviewTransformFullscreen(Matrix matrix, float aspectRatio) {
6936382c70a769b9ec94a3b0372ee27c0cd075e8be8Seth Raphael        mTextureViewHelper.updateTransformFullScreen(matrix, aspectRatio);
69402c129a598b6a165885fe950275675d62993d2eeSeth Raphael    }
69502c129a598b6a165885fe950275675d62993d2eeSeth Raphael
69602c129a598b6a165885fe950275675d62993d2eeSeth Raphael    /**
69702c129a598b6a165885fe950275675d62993d2eeSeth Raphael     * @return the rect that will display the preview.
69802c129a598b6a165885fe950275675d62993d2eeSeth Raphael     */
69902c129a598b6a165885fe950275675d62993d2eeSeth Raphael    public RectF getFullscreenRect() {
70002c129a598b6a165885fe950275675d62993d2eeSeth Raphael        return mTextureViewHelper.getFullscreenRect();
70102c129a598b6a165885fe950275675d62993d2eeSeth Raphael    }
70202c129a598b6a165885fe950275675d62993d2eeSeth Raphael
703b897a1e924394cb2196929975cf0c5cb542dd85cDoris Liu    /**
704b897a1e924394cb2196929975cf0c5cb542dd85cDoris Liu     * This is to support modules that calculate their own transform matrix because
705b897a1e924394cb2196929975cf0c5cb542dd85cDoris Liu     * they need to use a transform matrix to rotate the preview.
706b897a1e924394cb2196929975cf0c5cb542dd85cDoris Liu     *
707b897a1e924394cb2196929975cf0c5cb542dd85cDoris Liu     * @param matrix transform matrix to be set on the TextureView
708b897a1e924394cb2196929975cf0c5cb542dd85cDoris Liu     */
70970da918464276b110c43868caa272c97baadb89eDoris Liu    public void updatePreviewTransform(Matrix matrix) {
71070da918464276b110c43868caa272c97baadb89eDoris Liu        mTextureViewHelper.updateTransform(matrix);
711b897a1e924394cb2196929975cf0c5cb542dd85cDoris Liu    }
712b897a1e924394cb2196929975cf0c5cb542dd85cDoris Liu
713f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    public interface AnimationFinishedListener {
714f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        public void onAnimationFinished(boolean success);
715f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
716f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
717f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private class MyTouchListener implements View.OnTouchListener {
718f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        private boolean mScaleStarted = false;
719f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        @Override
720f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        public boolean onTouch(View v, MotionEvent event) {
721f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
722f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu                mScaleStarted = false;
723f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu            } else if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
724f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu                mScaleStarted = true;
725f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu            }
726f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu            return (!mScaleStarted) && mGestureDetector.onTouchEvent(event);
727f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        }
728f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
729f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
730f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    /**
731f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * This gesture listener finds out the direction of the scroll gestures and
732f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * sends them to CameraAppUI to do further handling.
733f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     */
734f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
735f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        private MotionEvent mDown;
736f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
737f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        @Override
738f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        public boolean onScroll(MotionEvent e1, MotionEvent ev, float distanceX, float distanceY) {
7392b906b8c9754b564d5113c7a342654c82f97f180Doris Liu            if (ev.getEventTime() - ev.getDownTime() > SWIPE_TIME_OUT_MS
740c050a9475312db95bcd6d3ec8480065ee8104954Spike Sprague                    || mSwipeState != IDLE
7418793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling                    || mIsCaptureIntent
7428793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling                    || !mSwipeEnabled) {
743b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu                return false;
744f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            }
745f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
746f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            int deltaX = (int) (ev.getX() - mDown.getX());
747f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            int deltaY = (int) (ev.getY() - mDown.getY());
748f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
749f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                if (Math.abs(deltaX) > mSlop || Math.abs(deltaY) > mSlop) {
750f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                    // Calculate the direction of the swipe.
751f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                    if (deltaX >= Math.abs(deltaY)) {
752f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                        // Swipe right.
753f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                        setSwipeState(SWIPE_RIGHT);
754f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                    } else if (deltaX <= -Math.abs(deltaY)) {
755f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                        // Swipe left.
756f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                        setSwipeState(SWIPE_LEFT);
757f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                    }
758f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                }
759f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            }
760f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            return true;
761f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        }
762f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
763f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        private void setSwipeState(int swipeState) {
764f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            mSwipeState = swipeState;
765f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            // Notify new swipe detected.
766f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            onSwipeDetected(swipeState);
767f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        }
768f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
769f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        @Override
770f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        public boolean onDown(MotionEvent ev) {
771f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            mDown = MotionEvent.obtain(ev);
772f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            mSwipeState = IDLE;
773f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu            return false;
774f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        }
775f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
776f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
777f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    public CameraAppUI(AppController controller, MainActivityLayout appRootView,
7788793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling            boolean isCaptureIntent) {
779f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mSlop = ViewConfiguration.get(controller.getAndroidContext()).getScaledTouchSlop();
780f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mController = controller;
781f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mIsCaptureIntent = isCaptureIntent;
782f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
783f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mAppRootView = appRootView;
784166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong        mFilmstripLayout = (FilmstripLayout) appRootView.findViewById(R.id.filmstrip_layout);
785b41034b16b0dce997544d2592db5029e7db4e238Doris Liu        mCameraRootView = (FrameLayout) appRootView.findViewById(R.id.camera_app_root);
786f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mModeTransitionView = (ModeTransitionView)
787f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                mAppRootView.findViewById(R.id.mode_transition_view);
7887ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong        mFilmstripBottomControls = new FilmstripBottomPanel(controller,
789001dc31f0b6e78b70db83c6d9b8cc7872e540965Angus Kong                (ViewGroup) mAppRootView.findViewById(R.id.filmstrip_bottom_panel));
790b2510252fb020f3ccb88787c870930427377b9dfAngus Kong        mFilmstripPanel = (FilmstripContentPanel) mAppRootView.findViewById(R.id.filmstrip_layout);
791f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mGestureDetector = new GestureDetector(controller.getAndroidContext(),
792f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                new MyGestureListener());
79328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        Resources res = controller.getAndroidContext().getResources();
79428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        mCaptureLayoutHelper = new CaptureLayoutHelper(
79528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu                res.getDimensionPixelSize(R.dimen.bottom_bar_height_min),
79628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu                res.getDimensionPixelSize(R.dimen.bottom_bar_height_max),
79728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu                res.getDimensionPixelSize(R.dimen.bottom_bar_height_optimal));
798f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mModeListView = (ModeListView) appRootView.findViewById(R.id.mode_list_layout);
799f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        if (mModeListView != null) {
800f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            mModeListView.setModeSwitchListener(this);
8012c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu            mModeListView.setModeListOpenListener(this);
802213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu            mModeListView.setCameraModuleScreenShotProvider(mCameraModuleScreenShotProvider);
80328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu            mModeListView.setCaptureLayoutHelper(mCaptureLayoutHelper);
80426aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu            boolean shouldShowSettingsCling = mController.getSettingsManager().getBoolean(
8056190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren                    SettingsManager.SCOPE_GLOBAL,
8066190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren                    Keys.KEY_SHOULD_SHOW_SETTINGS_BUTTON_CLING);
80726aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu            mModeListView.setShouldShowSettingsCling(shouldShowSettingsCling);
808f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        } else {
809f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            Log.e(TAG, "Cannot find mode list in the view hierarchy");
810f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        }
811f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mAnimationManager = new AnimationManager();
812427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        mRoundedThumbnailView = (RoundedThumbnailView) appRootView.findViewById(R.id.rounded_thumbnail_view);
813cb8f66b4953e4fed4a0cd5133c2914b26097c133Senpo Hu        mRoundedThumbnailView.setCallback(new RoundedThumbnailView.Callback() {
814427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu            @Override
815cb8f66b4953e4fed4a0cd5133c2914b26097c133Senpo Hu            public void onHitStateFinished() {
816427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu                mFilmstripLayout.showFilmstrip();
817427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu            }
818427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        });
819427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu
82028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        mAppRootView.setNonDecorWindowSizeChangedListener(mCaptureLayoutHelper);
82111ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu        initDisplayListener();
822256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling        mAccessibilityAffordances = mAppRootView.findViewById(R.id.accessibility_affordances);
823dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu        View modeListToggle = mAppRootView.findViewById(R.id.accessibility_mode_toggle_button);
824dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu        modeListToggle.setOnClickListener(new View.OnClickListener() {
825dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu            @Override
826dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu            public void onClick(View view) {
827256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling                openModeList();
828dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu            }
829dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu        });
830dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu        View filmstripToggle = mAppRootView.findViewById(
831dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu                R.id.accessibility_filmstrip_toggle_button);
832dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu        filmstripToggle.setOnClickListener(new View.OnClickListener() {
833dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu            @Override
834dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu            public void onClick(View view) {
835256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling                showFilmstrip();
836dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu            }
837dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu        });
838ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu
839ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu        mSuppressCaptureIndicator = false;
84011ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    }
84111ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu
8426809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu
8436809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu    /**
8446809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu     * Freeze what is currently shown on screen until the next preview frame comes
8456809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu     * in.
8466809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu     */
8476809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu    public void freezeScreenUntilPreviewReady() {
848c91c8d273b8884468dfd66a5b82526dc8245934eAlan Newberger        Log.v(TAG, "freezeScreenUntilPreviewReady");
8496809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu        mModeTransitionView.setupModeCover(mCameraModuleScreenShotProvider
8506809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                .getScreenShot(DOWN_SAMPLE_RATE_FOR_SCREENSHOT));
8516809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu        mHideCoverRunnable = new Runnable() {
8526809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu            @Override
8536809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu            public void run() {
8546809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu                mModeTransitionView.hideImageCover();
8556809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu            }
8566809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu        };
8576809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu        mModeCoverState = COVER_SHOWN;
8586809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu    }
8596809eb840f358430d3032c0532fb42d6dcfd06efDoris Liu
86011ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    /**
861e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     * Creates a cling for the specific viewer and links the cling to the corresponding
862e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     * button for layout position.
863e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     *
864e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     * @param viewerType defines which viewer the cling is for.
865e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     */
866e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    public void setupClingForViewer(int viewerType) {
867e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        if (viewerType == BottomPanel.VIEWER_REFOCUS) {
868e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            FrameLayout filmstripContent = (FrameLayout) mAppRootView
869e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                    .findViewById(R.id.camera_filmstrip_content_layout);
870e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            if (filmstripContent != null) {
871e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                // Creates refocus cling.
8728be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde                LayoutInflater inflater = AndroidServices.instance().provideLayoutInflater();
873e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                Cling refocusCling = (Cling) inflater.inflate(R.layout.cling_widget, null, false);
874e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                // Sets instruction text in the cling.
875e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                refocusCling.setText(mController.getAndroidContext().getResources()
876e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                        .getString(R.string.cling_text_for_refocus_editor_button));
877e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
878e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                // Adds cling into view hierarchy.
879e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                int clingWidth = mController.getAndroidContext()
880e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                        .getResources().getDimensionPixelSize(R.dimen.default_cling_width);
881e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                filmstripContent.addView(refocusCling, clingWidth,
882e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                        ViewGroup.LayoutParams.WRAP_CONTENT);
883e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                mFilmstripBottomControls.setClingForViewer(viewerType, refocusCling);
884e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            }
885e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        }
886e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    }
887e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
888e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    /**
889e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     * Clears the listeners for the cling and remove it from the view hierarchy.
890e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     *
891e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     * @param viewerType defines which viewer the cling is for.
892e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     */
893e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    public void clearClingForViewer(int viewerType) {
894e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        Cling clingToBeRemoved = mFilmstripBottomControls.getClingForViewer(viewerType);
895e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        if (clingToBeRemoved == null) {
896e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            // No cling is created for the specific viewer type.
897e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            return;
898e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        }
899e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        mFilmstripBottomControls.clearClingForViewer(viewerType);
900e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        clingToBeRemoved.setVisibility(View.GONE);
901e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        mAppRootView.removeView(clingToBeRemoved);
902e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    }
903e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
904e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    /**
9058793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling     * Enable or disable swipe gestures. We want to disable them e.g. while we
9068793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling     * record a video.
9078793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling     */
9088793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling    public void setSwipeEnabled(boolean enabled) {
9098793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling        mSwipeEnabled = enabled;
9109eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        // TODO: This can be removed once we come up with a new design for handling swipe
9119eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        // on shutter button and mode options. (More details: b/13751653)
9129eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        mAppRootView.setSwipeEnabled(enabled);
9138793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling    }
9148793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling
915846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling    public void onDestroy() {
9168be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde        AndroidServices.instance().provideDisplayManager()
917846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling                .unregisterDisplayListener(mDisplayListener);
918846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling    }
919846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling
9208793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling    /**
92111ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu     * Initializes the display listener to listen to display changes such as
92211ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu     * 180-degree rotation change, which will not have an onConfigurationChanged
92311ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu     * callback.
92411ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu     */
92511ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    private void initDisplayListener() {
92611ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu        if (ApiHelper.HAS_DISPLAY_LISTENER) {
9278be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde            mLastRotation = CameraUtil.getDisplayRotation();
92811ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu
92911ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu            mDisplayListener = new DisplayManager.DisplayListener() {
93011ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                @Override
93111ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                public void onDisplayAdded(int arg0) {
93211ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                    // Do nothing.
93311ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                }
93411ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu
93511ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                @Override
93611ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                public void onDisplayChanged(int displayId) {
93711ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                    int rotation = CameraUtil.getDisplayRotation(
9388be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde                    );
9396365bad43ff3e3e93d4e8c7e6dc22cbc96eb1aafDoris Liu                    if ((rotation - mLastRotation + 360) % 360 == 180
9406365bad43ff3e3e93d4e8c7e6dc22cbc96eb1aafDoris Liu                            && mPreviewStatusListener != null) {
94111ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                        mPreviewStatusListener.onPreviewFlipped();
942427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu                        mStickyBottomCaptureLayout.requestLayout();
943344320c90639f823451ddac42e8f39b74727787cDoris Liu                        mModeListView.requestLayout();
944344320c90639f823451ddac42e8f39b74727787cDoris Liu                        mTextureView.requestLayout();
94511ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                    }
94611ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                    mLastRotation = rotation;
94711ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                }
94811ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu
94911ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                @Override
95011ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                public void onDisplayRemoved(int arg0) {
95111ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                    // Do nothing.
95211ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu                }
95311ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu            };
95411ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu
9558be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde            AndroidServices.instance().provideDisplayManager()
9568be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde                  .registerDisplayListener(mDisplayListener, null);
95711ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu        }
958f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
959f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
960f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    /**
961f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * Redirects touch events to appropriate recipient views based on swipe direction.
962f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * More specifically, swipe up and swipe down will be handled by the view that handles
963f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * mode transition; swipe left will be send to filmstrip; swipe right will be redirected
964f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * to mode list in order to bring up mode list.
965f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     */
966f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private void onSwipeDetected(int swipeState) {
967f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        if (swipeState == SWIPE_UP || swipeState == SWIPE_DOWN) {
9689d52fc9e1a529012de83d1fea415c2fb4cba836cDoris Liu            // TODO: Polish quick switch after this release.
969bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu            // Quick switch between modes.
970bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu            int currentModuleIndex = mController.getCurrentModuleIndex();
971bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu            final int moduleToTransitionTo =
972bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu                    mController.getQuickSwitchToModuleId(currentModuleIndex);
973bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu            if (currentModuleIndex != moduleToTransitionTo) {
974f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                mAppRootView.redirectTouchEventsTo(mModeTransitionView);
9758992a26dd589310b2f45cbb01c158f324fd10289Alan Newberger                int shadeColorId = R.color.camera_gray_background;
976b520b97b89b0cf0389ea00d7e080971628cf6290Doris Liu                int iconRes = CameraUtil.getCameraModeCoverIconResId(moduleToTransitionTo,
977bd1b8f910d6f2c94daac304f4bd1a098939474c3Doris Liu                        mController.getAndroidContext());
978f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
979f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                AnimationFinishedListener listener = new AnimationFinishedListener() {
980ab05a742fb03b2016d2792c7b06f268d3dd82701Sascha Haeberling                    @Override
981f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                    public void onAnimationFinished(boolean success) {
982f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                        if (success) {
983e038c161389b5d1c0476e315736df31562328894Doris Liu                            mHideCoverRunnable = new Runnable() {
984e038c161389b5d1c0476e315736df31562328894Doris Liu                                @Override
985e038c161389b5d1c0476e315736df31562328894Doris Liu                                public void run() {
986e038c161389b5d1c0476e315736df31562328894Doris Liu                                    mModeTransitionView.startPeepHoleAnimation();
987e038c161389b5d1c0476e315736df31562328894Doris Liu                                }
988e038c161389b5d1c0476e315736df31562328894Doris Liu                            };
989e038c161389b5d1c0476e315736df31562328894Doris Liu                            mModeCoverState = COVER_SHOWN;
990f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                            // Go to new module when the previous operation is successful.
991f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                            mController.onModeSelected(moduleToTransitionTo);
992f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                        }
993f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                    }
994f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                };
995f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            }
996f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        } else if (swipeState == SWIPE_LEFT) {
997166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong            // Pass the touch sequence to filmstrip layout.
998166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong            mAppRootView.redirectTouchEventsTo(mFilmstripLayout);
999f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        } else if (swipeState == SWIPE_RIGHT) {
1000f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            // Pass the touch to mode switcher
1001f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            mAppRootView.redirectTouchEventsTo(mModeListView);
1002f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        }
1003f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
1004f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
1005f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    /**
10062b906b8c9754b564d5113c7a342654c82f97f180Doris Liu     * Gets called when activity resumes in preview.
10072b906b8c9754b564d5113c7a342654c82f97f180Doris Liu     */
10082b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    public void resume() {
1009b00d64307ae77541f8576593a29214d649fb94e9Doris Liu        // Show mode theme cover until preview is ready
1010b00d64307ae77541f8576593a29214d649fb94e9Doris Liu        showModeCoverUntilPreviewReady();
1011b00d64307ae77541f8576593a29214d649fb94e9Doris Liu
1012b2510252fb020f3ccb88787c870930427377b9dfAngus Kong        // Hide action bar first since we are in full screen mode first, and
1013b2510252fb020f3ccb88787c870930427377b9dfAngus Kong        // switch the system UI to lights-out mode.
1014b2510252fb020f3ccb88787c870930427377b9dfAngus Kong        mFilmstripPanel.hide();
1015dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu
1016d4c3333c99ece20b3125e86e1e3f6105b2bc9bddSascha Haeberling        // Show UI that is meant to only be used when spoken feedback is
1017d4c3333c99ece20b3125e86e1e3f6105b2bc9bddSascha Haeberling        // enabled.
1018b45f618d4a3aa068766be8741213080532feaaffSpike Sprague        mAccessibilityAffordances.setVisibility(
1019971ad50c0f220a396ffce50245617ff59ed0a09ezafir                (!mIsCaptureIntent && mAccessibilityUtil.isAccessibilityEnabled()) ? View.VISIBLE
1020971ad50c0f220a396ffce50245617ff59ed0a09ezafir                        : View.GONE);
1021256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling    }
1022dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu
1023256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling    /**
1024256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling     * Opens the mode list (e.g. because of the menu button being pressed) and
1025256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling     * adapts the rest of the UI.
1026256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling     */
1027256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling    public void openModeList() {
1028256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling        mModeOptionsOverlay.closeModeOptions();
1029256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling        mModeListView.onMenuPressed();
10302b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    }
10312b906b8c9754b564d5113c7a342654c82f97f180Doris Liu
1032971ad50c0f220a396ffce50245617ff59ed0a09ezafir    public void showAccessibilityZoomUI(float maxZoom) {
1033971ad50c0f220a396ffce50245617ff59ed0a09ezafir        mAccessibilityUtil.showZoomUI(maxZoom);
1034971ad50c0f220a396ffce50245617ff59ed0a09ezafir    }
1035971ad50c0f220a396ffce50245617ff59ed0a09ezafir
1036971ad50c0f220a396ffce50245617ff59ed0a09ezafir    public void hideAccessibilityZoomUI() {
1037971ad50c0f220a396ffce50245617ff59ed0a09ezafir        mAccessibilityUtil.hideZoomUI();
1038971ad50c0f220a396ffce50245617ff59ed0a09ezafir    }
1039971ad50c0f220a396ffce50245617ff59ed0a09ezafir
10402b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    /**
10412b906b8c9754b564d5113c7a342654c82f97f180Doris Liu     * A cover view showing the mode theme color and mode icon will be visible on
10422b906b8c9754b564d5113c7a342654c82f97f180Doris Liu     * top of preview until preview is ready (i.e. camera preview is started and
10432b906b8c9754b564d5113c7a342654c82f97f180Doris Liu     * the first frame has been received).
10442b906b8c9754b564d5113c7a342654c82f97f180Doris Liu     */
10452b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private void showModeCoverUntilPreviewReady() {
10462b906b8c9754b564d5113c7a342654c82f97f180Doris Liu        int modeId = mController.getCurrentModuleIndex();
10478992a26dd589310b2f45cbb01c158f324fd10289Alan Newberger        int colorId = R.color.camera_gray_background;;
1048b520b97b89b0cf0389ea00d7e080971628cf6290Doris Liu        int iconId = CameraUtil.getCameraModeCoverIconResId(modeId, mController.getAndroidContext());
10492b906b8c9754b564d5113c7a342654c82f97f180Doris Liu        mModeTransitionView.setupModeCover(colorId, iconId);
1050b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu        mHideCoverRunnable = new Runnable() {
1051b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu            @Override
1052b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu            public void run() {
1053b00d64307ae77541f8576593a29214d649fb94e9Doris Liu                mModeTransitionView.hideModeCover(null);
10544c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague                if (!mDisableAllUserInteractions) {
10554c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague                    showShimmyDelayed();
10564c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague                }
1057b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu            }
1058b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu        };
10592b906b8c9754b564d5113c7a342654c82f97f180Doris Liu        mModeCoverState = COVER_SHOWN;
10602b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    }
10612b906b8c9754b564d5113c7a342654c82f97f180Doris Liu
10622c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu    private void showShimmyDelayed() {
10632c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu        if (!mIsCaptureIntent) {
10642c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu            // Show shimmy in SHIMMY_DELAY_MS
10652ed67843b7eb5cb67eaec51561770262f5fd36c7Angus Kong            mModeListView.showModeSwitcherHint();
10662c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu        }
10672c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu    }
10682c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu
10692b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    private void hideModeCover() {
1070b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu        if (mHideCoverRunnable != null) {
1071b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu            mAppRootView.post(mHideCoverRunnable);
1072b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu            mHideCoverRunnable = null;
1073b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu        }
1074e038c161389b5d1c0476e315736df31562328894Doris Liu        mModeCoverState = COVER_HIDDEN;
1075a0e8347f9cfb583f90543635c5c86dc9252526e1Kevin Gabayan        if (mCoverHiddenTime < 0) {
1076a0e8347f9cfb583f90543635c5c86dc9252526e1Kevin Gabayan            mCoverHiddenTime = System.currentTimeMillis();
1077a0e8347f9cfb583f90543635c5c86dc9252526e1Kevin Gabayan        }
10782b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    }
10792b906b8c9754b564d5113c7a342654c82f97f180Doris Liu
1080dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu
1081dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu    public void onPreviewVisiblityChanged(int visibility) {
1082dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu        if (visibility == ModuleController.VISIBILITY_HIDDEN) {
1083dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu            setIndicatorBottomBarWrapperVisible(false);
1084256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling            mAccessibilityAffordances.setVisibility(View.GONE);
1085dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu        } else {
1086dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu            setIndicatorBottomBarWrapperVisible(true);
1087971ad50c0f220a396ffce50245617ff59ed0a09ezafir            if (!mIsCaptureIntent && mAccessibilityUtil.isAccessibilityEnabled()) {
1088256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling                mAccessibilityAffordances.setVisibility(View.VISIBLE);
1089dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu            } else {
1090256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling                mAccessibilityAffordances.setVisibility(View.GONE);
1091dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu            }
1092dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu        }
1093dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu    }
1094dfb5a6f356f3287c5cc9cac20948ec14c1f68a35Doris Liu
10951b1253241a5a9b3a59037ba7a626bca68a9b06d8Sam Judd    /**
1096d7064a6c6f1eb0748de8f56b8a1e006d60ab0f7eAlan Newberger     * Call to stop the preview from being rendered. Sets the entire capture
1097d7064a6c6f1eb0748de8f56b8a1e006d60ab0f7eAlan Newberger     * root view to invisible which includes the preview plus focus indicator
1098d7064a6c6f1eb0748de8f56b8a1e006d60ab0f7eAlan Newberger     * and any other auxiliary views for capture modes.
10991b1253241a5a9b3a59037ba7a626bca68a9b06d8Sam Judd     */
11001b1253241a5a9b3a59037ba7a626bca68a9b06d8Sam Judd    public void pausePreviewRendering() {
1101d7064a6c6f1eb0748de8f56b8a1e006d60ab0f7eAlan Newberger        mCameraRootView.setVisibility(View.INVISIBLE);
11021b1253241a5a9b3a59037ba7a626bca68a9b06d8Sam Judd    }
11031b1253241a5a9b3a59037ba7a626bca68a9b06d8Sam Judd
11041b1253241a5a9b3a59037ba7a626bca68a9b06d8Sam Judd    /**
1105d7064a6c6f1eb0748de8f56b8a1e006d60ab0f7eAlan Newberger     * Call to begin rendering the preview and auxiliary views again.
11061b1253241a5a9b3a59037ba7a626bca68a9b06d8Sam Judd     */
11071b1253241a5a9b3a59037ba7a626bca68a9b06d8Sam Judd    public void resumePreviewRendering() {
1108d7064a6c6f1eb0748de8f56b8a1e006d60ab0f7eAlan Newberger        mCameraRootView.setVisibility(View.VISIBLE);
11091b1253241a5a9b3a59037ba7a626bca68a9b06d8Sam Judd    }
11101b1253241a5a9b3a59037ba7a626bca68a9b06d8Sam Judd
111108b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling    /**
111208b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling     * Returns the transform associated with the preview view.
111308b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling     *
111408b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling     * @param m the Matrix in which to copy the current transform.
111508b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling     * @return The specified matrix if not null or a new Matrix instance
111608b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling     *         otherwise.
111708b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling     */
111808b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling    public Matrix getPreviewTransform(Matrix m) {
111908b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling        return mTextureView.getTransform(m);
112008b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling    }
112108b3c94a7d7aff30b5da8e99649346e37b67a5c5Sascha Haeberling
11222c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu    @Override
11232c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu    public void onOpenFullScreen() {
11242ed67843b7eb5cb67eaec51561770262f5fd36c7Angus Kong        // Do nothing.
11252c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu    }
11262c559c4bd3c65e0cb0bca06f30e3bc979038e6f7Doris Liu
11279d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    @Override
11289d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    public void onModeListOpenProgress(float progress) {
11291908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde        // When the mode list is in transition, ensure the large layers are
11301908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde        // hardware accelerated.
11317543914f2de33b1be25626afb31fa979b06dd582Paul Rohde        if (progress >= 1.0f || progress <= 0.0f) {
11327543914f2de33b1be25626afb31fa979b06dd582Paul Rohde            // Convert hardware layers back to default layer types when animation stops
11337543914f2de33b1be25626afb31fa979b06dd582Paul Rohde            // to prevent accidental artifacting.
11347543914f2de33b1be25626afb31fa979b06dd582Paul Rohde            if(mModeOptionsToggle.getLayerType() == View.LAYER_TYPE_HARDWARE ||
11357543914f2de33b1be25626afb31fa979b06dd582Paul Rohde                  mShutterButton.getLayerType() == View.LAYER_TYPE_HARDWARE) {
11367543914f2de33b1be25626afb31fa979b06dd582Paul Rohde                Log.v(TAG, "Disabling hardware layer for the Mode Options Toggle Button.");
11377543914f2de33b1be25626afb31fa979b06dd582Paul Rohde                mModeOptionsToggle.setLayerType(View.LAYER_TYPE_NONE, null);
11387543914f2de33b1be25626afb31fa979b06dd582Paul Rohde                Log.v(TAG, "Disabling hardware layer for the Shutter Button.");
11397543914f2de33b1be25626afb31fa979b06dd582Paul Rohde                mShutterButton.setLayerType(View.LAYER_TYPE_NONE, null);
11407543914f2de33b1be25626afb31fa979b06dd582Paul Rohde            }
11417543914f2de33b1be25626afb31fa979b06dd582Paul Rohde        } else {
11427543914f2de33b1be25626afb31fa979b06dd582Paul Rohde            if(mModeOptionsToggle.getLayerType() != View.LAYER_TYPE_HARDWARE ||
11437543914f2de33b1be25626afb31fa979b06dd582Paul Rohde                  mShutterButton.getLayerType() != View.LAYER_TYPE_HARDWARE) {
11447543914f2de33b1be25626afb31fa979b06dd582Paul Rohde                Log.v(TAG, "Enabling hardware layer for the Mode Options Toggle Button.");
11457543914f2de33b1be25626afb31fa979b06dd582Paul Rohde                mModeOptionsToggle.setLayerType(View.LAYER_TYPE_HARDWARE, null);
11467543914f2de33b1be25626afb31fa979b06dd582Paul Rohde                Log.v(TAG, "Enabling hardware layer for the Shutter Button.");
11477543914f2de33b1be25626afb31fa979b06dd582Paul Rohde                mShutterButton.setLayerType(View.LAYER_TYPE_HARDWARE, null);
11487543914f2de33b1be25626afb31fa979b06dd582Paul Rohde            }
11491908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde        }
11501908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde
11519d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu        progress = 1 - progress;
11529d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu        float interpolatedProgress = Gusterpolator.INSTANCE.getInterpolation(progress);
11539d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu        mModeOptionsToggle.setAlpha(interpolatedProgress);
1154948de99e58b72e815224d4e12761863dfceffae0Doris Liu        // Change shutter button alpha linearly based on the mode list open progress:
1155948de99e58b72e815224d4e12761863dfceffae0Doris Liu        // set the alpha to disabled alpha when list is fully open, to enabled alpha
1156948de99e58b72e815224d4e12761863dfceffae0Doris Liu        // when the list is fully closed.
1157948de99e58b72e815224d4e12761863dfceffae0Doris Liu        mShutterButton.setAlpha(progress * ShutterButton.ALPHA_WHEN_ENABLED
1158948de99e58b72e815224d4e12761863dfceffae0Doris Liu                + (1 - progress) * ShutterButton.ALPHA_WHEN_DISABLED);
11599d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    }
11609d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu
11619d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    @Override
11629d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    public void onModeListClosed() {
11631908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde        // Convert hardware layers back to default layer types when animation stops
11641908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde        // to prevent accidental artifacting.
11657543914f2de33b1be25626afb31fa979b06dd582Paul Rohde        if(mModeOptionsToggle.getLayerType() == View.LAYER_TYPE_HARDWARE ||
11667543914f2de33b1be25626afb31fa979b06dd582Paul Rohde              mShutterButton.getLayerType() == View.LAYER_TYPE_HARDWARE) {
11671908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde            Log.v(TAG, "Disabling hardware layer for the Mode Options Toggle Button.");
11681908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde            mModeOptionsToggle.setLayerType(View.LAYER_TYPE_NONE, null);
11691908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde            Log.v(TAG, "Disabling hardware layer for the Shutter Button.");
11701908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde            mShutterButton.setLayerType(View.LAYER_TYPE_NONE, null);
11711908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde        }
11721908beee07fe9792338dbf8e0c36a5f1e3e9401fPaul Rohde
11739d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu        // Make sure the alpha on mode options ellipse is reset when mode drawer
11749d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu        // is closed.
11759d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu        mModeOptionsToggle.setAlpha(1f);
1176948de99e58b72e815224d4e12761863dfceffae0Doris Liu        mShutterButton.setAlpha(ShutterButton.ALPHA_WHEN_ENABLED);
11779d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    }
11789d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu
11792b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    /**
1180166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong     * Called when the back key is pressed.
1181166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong     *
1182166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong     * @return Whether the UI responded to the key event.
1183166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong     */
1184166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong    public boolean onBackPressed() {
1185b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu        if (mFilmstripLayout.getVisibility() == View.VISIBLE) {
1186b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu            return mFilmstripLayout.onBackPressed();
1187b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu        } else {
1188b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu            return mModeListView.onBackPressed();
1189b9b7240d62dd2ad245f2c0e09fd1056a28687978Doris Liu        }
1190166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong    }
1191166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong
1192166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong    /**
119306db742814dd635d100639f977fcfdc904deb778Doris Liu     * Sets a {@link com.android.camera.ui.PreviewStatusListener} that
11941648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren     * listens to SurfaceTexture changes. In addition, listeners are set on
11951648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren     * dependent app ui elements.
119606db742814dd635d100639f977fcfdc904deb778Doris Liu     *
119706db742814dd635d100639f977fcfdc904deb778Doris Liu     * @param previewStatusListener the listener that gets notified when SurfaceTexture
119806db742814dd635d100639f977fcfdc904deb778Doris Liu     *                              changes
119906db742814dd635d100639f977fcfdc904deb778Doris Liu     */
120006db742814dd635d100639f977fcfdc904deb778Doris Liu    public void setPreviewStatusListener(PreviewStatusListener previewStatusListener) {
120106db742814dd635d100639f977fcfdc904deb778Doris Liu        mPreviewStatusListener = previewStatusListener;
120206db742814dd635d100639f977fcfdc904deb778Doris Liu        if (mPreviewStatusListener != null) {
12031648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren            onPreviewListenerChanged();
12041648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren        }
12051648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren    }
12061648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren
12071648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren    /**
12081648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren     * When the PreviewStatusListener changes, listeners need to be
12091648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren     * set on the following app ui elements:
12101648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren     * {@link com.android.camera.ui.PreviewOverlay},
12111648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren     * {@link com.android.camera.ui.BottomBar},
1212e2a1f54fbf6a8a7beff5b7695654ca21e63643afErin Dahlgren     * {@link com.android.camera.ui.IndicatorIconController}.
12131648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren     */
12141648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren    private void onPreviewListenerChanged() {
12151648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren        // Set a listener for recognizing preview gestures.
12161648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren        GestureDetector.OnGestureListener gestureListener
12171648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren            = mPreviewStatusListener.getGestureListener();
12181648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren        if (gestureListener != null) {
12191648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren            mPreviewOverlay.setGestureListener(gestureListener);
12201648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren        }
1221d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        View.OnTouchListener touchListener = mPreviewStatusListener.getTouchListener();
1222d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        if (touchListener != null) {
1223d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            mPreviewOverlay.setTouchListener(touchListener);
1224d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        }
12251648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren
12261648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren        mTextureViewHelper.setAutoAdjustTransform(
1227b259701e4f421b10404425d2a827cbe9d2571585Angus Kong                mPreviewStatusListener.shouldAutoAdjustTransformMatrixOnLayout());
12281648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren    }
12291648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren
12301648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren    /**
12311648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren     * This method should be called in onCameraOpened.  It defines CameraAppUI
12321648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren     * specific changes that depend on the camera or camera settings.
12331648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren     */
12341648c36927501ff32bf2918e8a445118d5208731Erin Dahlgren    public void onChangeCamera() {
1235b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        ModuleController moduleController = mController.getCurrentModuleController();
1236ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava        HardwareSpec hardwareSpec = moduleController.getHardwareSpec();
1237ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava
1238ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava        /**
1239ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava         * The current UI requires that the flash option visibility in front-
1240ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava         * facing camera be
1241ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava         *   * disabled if back facing camera supports flash
1242ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava         *   * hidden if back facing camera does not support flash
1243ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava         * We save whether back facing camera supports flash because we cannot
1244ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava         * get this in front facing camera without a camera switch.
1245ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava         *
1246ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava         * If this preference is cleared, we also need to clear the camera
1247ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava         * facing setting so we default to opening the camera in back facing
1248ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava         * camera, and can save this flash support value again.
1249ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava         */
1250f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava        if (hardwareSpec != null) {
1251f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava            if (!mController.getSettingsManager().isSet(SettingsManager.SCOPE_GLOBAL,
1252f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                    Keys.KEY_FLASH_SUPPORTED_BACK_CAMERA)) {
1253f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                mController.getSettingsManager().set(SettingsManager.SCOPE_GLOBAL,
1254f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                        Keys.KEY_FLASH_SUPPORTED_BACK_CAMERA,
1255f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                        hardwareSpec.isFlashSupported());
1256f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava            }
1257f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava            /** Similar logic applies to the HDR option. */
1258f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava            if (!mController.getSettingsManager().isSet(SettingsManager.SCOPE_GLOBAL,
1259f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                    Keys.KEY_HDR_SUPPORT_MODE_BACK_CAMERA)) {
1260f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                String hdrSupportMode;
1261f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                if (hardwareSpec.isHdrPlusSupported()) {
1262f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                    hdrSupportMode = getResourceString(
1263f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                            R.string.pref_camera_hdr_supportmode_hdr_plus);
1264f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                } else if (hardwareSpec.isHdrSupported()) {
1265f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                    hdrSupportMode = getResourceString(R.string.pref_camera_hdr_supportmode_hdr);
1266f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                } else {
1267f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                    hdrSupportMode = getResourceString(R.string.pref_camera_hdr_supportmode_none);
1268f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                }
1269f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                mController.getSettingsManager().set(SettingsManager.SCOPE_GLOBAL,
1270f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava                        Keys.KEY_HDR_SUPPORT_MODE_BACK_CAMERA, hdrSupportMode);
1271f361659dd9ab34087276b2514a766eadafe344aeGabriel Nava            }
1272ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava        }
1273ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava
1274ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava        applyModuleSpecs(hardwareSpec, moduleController.getBottomBarSpec(),
1275ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                true /*skipScopeCheck*/);
12768c50948fce260d0614daed71fc53ca5bf0e98060Senpo Hu        syncModeOptionIndicators();
12778c50948fce260d0614daed71fc53ca5bf0e98060Senpo Hu    }
1278b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
12798c50948fce260d0614daed71fc53ca5bf0e98060Senpo Hu    /**
12808c50948fce260d0614daed71fc53ca5bf0e98060Senpo Hu     * Updates the mode option indicators according to the current settings.
12818c50948fce260d0614daed71fc53ca5bf0e98060Senpo Hu     */
12828c50948fce260d0614daed71fc53ca5bf0e98060Senpo Hu    public void syncModeOptionIndicators() {
1283e2a1f54fbf6a8a7beff5b7695654ca21e63643afErin Dahlgren        if (mIndicatorIconController != null) {
12841848494bd09c85002d8c59d4feb8a6e0dc32871fErin Dahlgren            // Sync the settings state with the indicator state.
1285a906809bd3e67f3ceaa070baefbdca8c9cb3d766Erin Dahlgren            mIndicatorIconController.syncIndicators();
128606db742814dd635d100639f977fcfdc904deb778Doris Liu        }
128706db742814dd635d100639f977fcfdc904deb778Doris Liu    }
128806db742814dd635d100639f977fcfdc904deb778Doris Liu
128906db742814dd635d100639f977fcfdc904deb778Doris Liu    /**
12902bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong     * Adds a listener to receive callbacks when preview area changes.
1291482de029dc20e0a577388a602985fb31c3200309Doris Liu     */
12922bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong    public void addPreviewAreaChangedListener(
12932bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong            PreviewStatusListener.PreviewAreaChangedListener listener) {
1294482de029dc20e0a577388a602985fb31c3200309Doris Liu        mTextureViewHelper.addPreviewAreaSizeChangedListener(listener);
1295482de029dc20e0a577388a602985fb31c3200309Doris Liu    }
1296482de029dc20e0a577388a602985fb31c3200309Doris Liu
1297482de029dc20e0a577388a602985fb31c3200309Doris Liu    /**
12982bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong     * Removes a listener that receives callbacks when preview area changes.
1299482de029dc20e0a577388a602985fb31c3200309Doris Liu     */
13002bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong    public void removePreviewAreaChangedListener(
13012bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong            PreviewStatusListener.PreviewAreaChangedListener listener) {
1302482de029dc20e0a577388a602985fb31c3200309Doris Liu        mTextureViewHelper.removePreviewAreaSizeChangedListener(listener);
1303482de029dc20e0a577388a602985fb31c3200309Doris Liu    }
1304482de029dc20e0a577388a602985fb31c3200309Doris Liu
1305482de029dc20e0a577388a602985fb31c3200309Doris Liu    /**
1306f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * This inflates generic_module layout, which contains all the shared views across
1307f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * modules. Then each module inflates their own views in the given view group. For
1308f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * now, this is called every time switching from a not-yet-refactored module to a
1309f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * refactored module. In the future, this should only need to be done once per app
1310f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * start.
1311f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     */
1312f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    public void prepareModuleUI() {
13133c62221afd869828ba867fce15755a582f2c2334Erin Dahlgren        mController.getSettingsManager().addListener(this);
1314c6c9740d996bf073a157721aa3eb2a1aa60c477dDoris Liu        mModuleUI = (FrameLayout) mCameraRootView.findViewById(R.id.module_layout);
1315f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mTextureView = (TextureView) mCameraRootView.findViewById(R.id.preview_content);
13168c8fb114ad4e121c4c1f3d726632dffbb32bda13Sol Boucher        mTextureViewHelper = new TextureViewHelper(mTextureView, mCaptureLayoutHelper,
1317f018bce18af5626bf67e6dcb37ea60b0cc6a53cdI-Jong Lin                mController.getCameraProvider(), mController);
131870da918464276b110c43868caa272c97baadb89eDoris Liu        mTextureViewHelper.setSurfaceTextureListener(this);
131970da918464276b110c43868caa272c97baadb89eDoris Liu        mTextureViewHelper.setOnLayoutChangeListener(mPreviewLayoutChangeListener);
132070da918464276b110c43868caa272c97baadb89eDoris Liu
13210a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        mBottomBar = (BottomBar) mCameraRootView.findViewById(R.id.bottom_bar);
1322d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        int unpressedColor = mController.getAndroidContext().getResources()
13238992a26dd589310b2f45cbb01c158f324fd10289Alan Newberger            .getColor(R.color.camera_gray_background);
1324d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        setBottomBarColor(unpressedColor);
1325d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        updateModeSpecificUIColors();
1326d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
132728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        mBottomBar.setCaptureLayoutHelper(mCaptureLayoutHelper);
1328d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1329165bb8d85e6eab4e261c6b21a754ee227f732795Erin Dahlgren        mModeOptionsOverlay
1330165bb8d85e6eab4e261c6b21a754ee227f732795Erin Dahlgren            = (ModeOptionsOverlay) mCameraRootView.findViewById(R.id.mode_options_overlay);
1331d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1332d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        // Sets the visibility of the bottom bar and the mode options.
1333d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        resetBottomControls(mController.getCurrentModuleController(),
1334d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            mController.getCurrentModuleIndex());
133528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        mModeOptionsOverlay.setCaptureLayoutHelper(mCaptureLayoutHelper);
133656688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
13375d18769f53db81d401488811250570290a73626bErin Dahlgren        mShutterButton = (ShutterButton) mCameraRootView.findViewById(R.id.shutter_button);
13385d18769f53db81d401488811250570290a73626bErin Dahlgren        addShutterListener(mController.getCurrentModuleController());
13395d18769f53db81d401488811250570290a73626bErin Dahlgren        addShutterListener(mModeOptionsOverlay);
1340a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren        addShutterListener(this);
13415d18769f53db81d401488811250570290a73626bErin Dahlgren
1342b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren        mGridLines = (GridLines) mCameraRootView.findViewById(R.id.grid_lines);
1343b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren        mTextureViewHelper.addPreviewAreaSizeChangedListener(mGridLines);
1344b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren
1345f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        mPreviewOverlay = (PreviewOverlay) mCameraRootView.findViewById(R.id.preview_overlay);
1346f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        mPreviewOverlay.setOnTouchListener(new MyTouchListener());
1347165bb8d85e6eab4e261c6b21a754ee227f732795Erin Dahlgren        mPreviewOverlay.setOnPreviewTouchedListener(mModeOptionsOverlay);
1348971ad50c0f220a396ffce50245617ff59ed0a09ezafir        mAccessibilityUtil = new AccessibilityUtil(mPreviewOverlay, mAccessibilityAffordances);
134956688f7019fbe4dee110b7600349f48da9fff601Erin Dahlgren
13501dfe7828fd60741b9752553af3ee439c04e758a0Doris Liu        mCaptureOverlay = (CaptureAnimationOverlay)
13511dfe7828fd60741b9752553af3ee439c04e758a0Doris Liu                mCameraRootView.findViewById(R.id.capture_overlay);
1352ca4a5668c5bcda027bd896ebf17c8ef374e2ac75Doris Liu        mTextureViewHelper.addPreviewAreaSizeChangedListener(mPreviewOverlay);
1353ca4a5668c5bcda027bd896ebf17c8ef374e2ac75Doris Liu        mTextureViewHelper.addPreviewAreaSizeChangedListener(mCaptureOverlay);
13544efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
1355e2a1f54fbf6a8a7beff5b7695654ca21e63643afErin Dahlgren        if (mIndicatorIconController == null) {
1356e2a1f54fbf6a8a7beff5b7695654ca21e63643afErin Dahlgren            mIndicatorIconController =
1357e2a1f54fbf6a8a7beff5b7695654ca21e63643afErin Dahlgren                new IndicatorIconController(mController, mAppRootView);
1358e2a1f54fbf6a8a7beff5b7695654ca21e63643afErin Dahlgren        }
1359f1b2e407b20ff16fe793158c598e59799c1990efErin Dahlgren
1360f1b2e407b20ff16fe793158c598e59799c1990efErin Dahlgren        mController.getButtonManager().load(mCameraRootView);
1361e2a1f54fbf6a8a7beff5b7695654ca21e63643afErin Dahlgren        mController.getButtonManager().setListener(mIndicatorIconController);
13626e07fe22cf84e9eea02d368bf64ab68d92401f20Erin Dahlgren        mController.getSettingsManager().addListener(mIndicatorIconController);
13639d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu
13649d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu        mModeOptionsToggle = mCameraRootView.findViewById(R.id.mode_options_toggle);
1365987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        mFocusRing = (FocusRing) mCameraRootView.findViewById(R.id.focus_ring);
13661e0810c88e791d0f658eb5a6f95d771ee03a7631Sascha Haeberling        mTutorialsPlaceHolderWrapper = (FrameLayout) mCameraRootView
13671e0810c88e791d0f658eb5a6f95d771ee03a7631Sascha Haeberling                .findViewById(R.id.tutorials_placeholder_wrapper);
1368427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        mStickyBottomCaptureLayout = (StickyBottomCaptureLayout) mAppRootView
1369427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu                .findViewById(R.id.sticky_bottom_capture_layout);
1370427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        mStickyBottomCaptureLayout.setCaptureLayoutHelper(mCaptureLayoutHelper);
137164d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling        mCountdownCancelButton = (ImageButton) mStickyBottomCaptureLayout
137264d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling                .findViewById(R.id.shutter_cancel_button);
1373b259701e4f421b10404425d2a827cbe9d2571585Angus Kong
1374b908d933736a4ec042aad065b7ebf2059bbcac97Doris Liu        mTextureViewHelper.addPreviewAreaSizeChangedListener(mModeListView);
137528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        mTextureViewHelper.addAspectRatioChangedListener(
137628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu                new PreviewStatusListener.PreviewAspectRatioChangedListener() {
137728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu                    @Override
137828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu                    public void onPreviewAspectRatioChanged(float aspectRatio) {
137928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu                        mModeOptionsOverlay.requestLayout();
138028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu                        mBottomBar.requestLayout();
138128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu                    }
1382344320c90639f823451ddac42e8f39b74727787cDoris Liu                }
1383344320c90639f823451ddac42e8f39b74727787cDoris Liu        );
1384f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
1385f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
1386f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    /**
1387f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * Called indirectly from each module in their initialization to get a view group
1388f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * to inflate the module specific views in.
1389f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     *
1390f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * @return a view group for modules to attach views to
1391f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     */
1392c6c9740d996bf073a157721aa3eb2a1aa60c477dDoris Liu    public FrameLayout getModuleRootView() {
1393b41034b16b0dce997544d2592db5029e7db4e238Doris Liu        // TODO: Change it to mModuleUI when refactor is done
1394b41034b16b0dce997544d2592db5029e7db4e238Doris Liu        return mCameraRootView;
1395f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
1396f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
1397f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    /**
1398f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * Remove all the module specific views.
1399f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     */
1400f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    public void clearModuleUI() {
1401f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        if (mModuleUI != null) {
1402f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            mModuleUI.removeAllViews();
1403f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        }
14045d18769f53db81d401488811250570290a73626bErin Dahlgren        removeShutterListener(mController.getCurrentModuleController());
14051e0810c88e791d0f658eb5a6f95d771ee03a7631Sascha Haeberling        mTutorialsPlaceHolderWrapper.removeAllViews();
1406de7633bbcfb08865175126713d97132086bff340Sascha Haeberling        mTutorialsPlaceHolderWrapper.setVisibility(View.GONE);
14070744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
140859efb9af8340a5e3500037b23fb3ac16011a1c7eSeth Raphael        setShutterButtonEnabled(true);
140906db742814dd635d100639f977fcfdc904deb778Doris Liu        mPreviewStatusListener = null;
1410f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        mPreviewOverlay.reset();
1411987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
1412987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        Log.v(TAG, "mFocusRing.stopFocusAnimations()");
1413987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        mFocusRing.stopFocusAnimations();
1414f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
1415f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
14162b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    /**
14175a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu     * Gets called when preview is ready to start. It sets up one shot preview callback
14185a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu     * in order to receive a callback when the preview frame is available, so that
14195a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu     * the preview cover can be hidden to reveal preview.
14205a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu     *
14215a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu     * An alternative for getting the timing to hide preview cover is through
14225a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu     * {@link CameraAppUI#onSurfaceTextureUpdated(android.graphics.SurfaceTexture)},
14235a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu     * which is less accurate but therefore is the fallback for modules that manage
14245a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu     * their own preview callbacks (as setting one preview callback will override
14255a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu     * any other installed preview callbacks), or use camera2 API.
14265a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu     */
14275a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu    public void onPreviewReadyToStart() {
14285a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu        if (mModeCoverState == COVER_SHOWN) {
14295a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu            mModeCoverState = COVER_WILL_HIDE_AT_NEXT_FRAME;
14305a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu            mController.setupOneShotPreviewListener();
14315a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu        }
14325a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu    }
14335a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu
14345a367545ab931a308c8d8555ef5a747dc9565cafDoris Liu    /**
14352b906b8c9754b564d5113c7a342654c82f97f180Doris Liu     * Gets called when preview is started.
14362b906b8c9754b564d5113c7a342654c82f97f180Doris Liu     */
14372b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    public void onPreviewStarted() {
1438c91c8d273b8884468dfd66a5b82526dc8245934eAlan Newberger        Log.v(TAG, "onPreviewStarted");
14392b906b8c9754b564d5113c7a342654c82f97f180Doris Liu        if (mModeCoverState == COVER_SHOWN) {
14407e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin            // This is a work around of the face detection failure in b/20724126.
14417e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin            // In particular, we need to drop the first preview frame in order to
14427e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin            // make face detection work and also need to hide this preview frame to
14437e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin            // avoid potential janks. We do this only for L, Nexus 6 and Haleakala.
14447e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin            if (ApiHelper.isLorLMr1() && ApiHelper.IS_NEXUS_6) {
14457e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin                mModeCoverState = COVER_WILL_HIDE_AFTER_NEXT_TEXTURE_UPDATE;
14467e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin            } else {
14477e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin                mModeCoverState = COVER_WILL_HIDE_AT_NEXT_TEXTURE_UPDATE;
14487e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin            }
14492b906b8c9754b564d5113c7a342654c82f97f180Doris Liu        }
1450a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren        enableModeOptions();
14512b906b8c9754b564d5113c7a342654c82f97f180Doris Liu    }
14522b906b8c9754b564d5113c7a342654c82f97f180Doris Liu
1453b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu    /**
14544d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu     * Gets notified when next preview frame comes in.
14554d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu     */
14564d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu    public void onNewPreviewFrame() {
1457c91c8d273b8884468dfd66a5b82526dc8245934eAlan Newberger        Log.v(TAG, "onNewPreviewFrame");
14587cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        CameraPerformanceTracker.onEvent(CameraPerformanceTracker.FIRST_PREVIEW_FRAME);
14594d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu        hideModeCover();
14604d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu    }
14614d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu
1462a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren    @Override
1463a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren    public void onShutterButtonClick() {
1464a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren        /*
1465a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren         * Set the mode options toggle unclickable, generally
1466a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren         * throughout the app, whenever the shutter button is clicked.
1467a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren         *
1468a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren         * This could be done in the OnShutterButtonListener of the
1469a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren         * ModeOptionsOverlay, but since it is very important that we
1470a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren         * can clearly see when the toggle becomes clickable again,
1471a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren         * keep all of that logic at this level.
1472a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren         */
14730d32f29b2a82c2afa87b46e309c38f67f8b5e54cPuneet Lall        // disableModeOptions();
1474a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren    }
1475a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren
1476a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren    @Override
1477b7c7d9a067cd52a27cfbaf0714a2074f972d836dAndy Huibers    public void onShutterCoordinate(TouchCoordinate coord) {
1478b7c7d9a067cd52a27cfbaf0714a2074f972d836dAndy Huibers        // Do nothing.
1479b7c7d9a067cd52a27cfbaf0714a2074f972d836dAndy Huibers    }
1480b7c7d9a067cd52a27cfbaf0714a2074f972d836dAndy Huibers
1481b7c7d9a067cd52a27cfbaf0714a2074f972d836dAndy Huibers    @Override
1482a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren    public void onShutterButtonFocus(boolean pressed) {
1483a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren        // noop
1484a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren    }
1485a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren
148682d592f64966766ac4e4181e08b0d2989d4ed9c3Shashi Shekhar    @Override
148782d592f64966766ac4e4181e08b0d2989d4ed9c3Shashi Shekhar    public void onShutterButtonLongPressed() {
148882d592f64966766ac4e4181e08b0d2989d4ed9c3Shashi Shekhar        // noop
148982d592f64966766ac4e4181e08b0d2989d4ed9c3Shashi Shekhar    }
149082d592f64966766ac4e4181e08b0d2989d4ed9c3Shashi Shekhar
1491a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren    /**
1492c19d97b385261312399b67b538f8faa074314bebSpike Sprague     * Set the mode options toggle clickable.
1493c19d97b385261312399b67b538f8faa074314bebSpike Sprague     */
1494c19d97b385261312399b67b538f8faa074314bebSpike Sprague    public void enableModeOptions() {
1495c19d97b385261312399b67b538f8faa074314bebSpike Sprague        /*
1496c19d97b385261312399b67b538f8faa074314bebSpike Sprague         * For modules using camera 1 api, this gets called in
1497c19d97b385261312399b67b538f8faa074314bebSpike Sprague         * onSurfaceTextureUpdated whenever the preview gets stopped and
1498c19d97b385261312399b67b538f8faa074314bebSpike Sprague         * started after each capture.  This also takes care of the
1499c19d97b385261312399b67b538f8faa074314bebSpike Sprague         * case where the mode options might be unclickable when we
1500c19d97b385261312399b67b538f8faa074314bebSpike Sprague         * switch modes
1501c19d97b385261312399b67b538f8faa074314bebSpike Sprague         *
1502c19d97b385261312399b67b538f8faa074314bebSpike Sprague         * For modules using camera 2 api, they're required to call this
1503c19d97b385261312399b67b538f8faa074314bebSpike Sprague         * method when a capture is "completed".  Unfortunately this differs
1504c19d97b385261312399b67b538f8faa074314bebSpike Sprague         * per module implementation.
1505c19d97b385261312399b67b538f8faa074314bebSpike Sprague         */
1506d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague        if (!mDisableAllUserInteractions) {
1507d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague            mModeOptionsOverlay.setToggleClickable(true);
1508d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague        }
1509c19d97b385261312399b67b538f8faa074314bebSpike Sprague    }
1510c19d97b385261312399b67b538f8faa074314bebSpike Sprague
1511c19d97b385261312399b67b538f8faa074314bebSpike Sprague    /**
1512c19d97b385261312399b67b538f8faa074314bebSpike Sprague     * Set the mode options toggle not clickable.
1513c19d97b385261312399b67b538f8faa074314bebSpike Sprague     */
1514c19d97b385261312399b67b538f8faa074314bebSpike Sprague    public void disableModeOptions() {
1515c19d97b385261312399b67b538f8faa074314bebSpike Sprague        mModeOptionsOverlay.setToggleClickable(false);
1516c19d97b385261312399b67b538f8faa074314bebSpike Sprague    }
1517c19d97b385261312399b67b538f8faa074314bebSpike Sprague
1518d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague    public void setDisableAllUserInteractions(boolean disable) {
1519d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague        if (disable) {
1520d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague            disableModeOptions();
1521d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague            setShutterButtonEnabled(false);
1522d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague            setSwipeEnabled(false);
15234c96d840aeff669011a9e8697cbac77fe8f4eda2Spike Sprague            mModeListView.hideAnimated();
1524d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague        } else {
1525d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague            enableModeOptions();
1526d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague            setShutterButtonEnabled(true);
1527d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague            setSwipeEnabled(true);
1528d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague        }
1529d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague        mDisableAllUserInteractions = disable;
1530d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague    }
1531d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague
1532427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    @Override
1533427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    public void onModeButtonPressed(int modeIndex) {
1534427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        // TODO: Make CameraActivity listen to ModeListView's events.
1535427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        int pressedModuleId = mController.getModuleId(modeIndex);
1536427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        int currentModuleId = mController.getCurrentModuleIndex();
1537427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        if (pressedModuleId != currentModuleId) {
1538427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu            hideCaptureIndicator();
1539427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        }
1540427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    }
1541427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu
1542c19d97b385261312399b67b538f8faa074314bebSpike Sprague    /**
1543b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu     * Gets called when a mode is selected from {@link com.android.camera.ui.ModeListView}
1544b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu     *
1545b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu     * @param modeIndex mode index of the selected mode
1546b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu     */
1547f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    @Override
1548f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    public void onModeSelected(int modeIndex) {
1549b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu        mHideCoverRunnable = new Runnable() {
1550b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu            @Override
1551b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu            public void run() {
1552b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu                mModeListView.startModeSelectionAnimation();
1553b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu            }
1554b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu        };
1555a16219d51937bda5f3e69c0e77171ae0fb893823Spike Sprague        mShutterButton.setAlpha(ShutterButton.ALPHA_WHEN_ENABLED);
1556e038c161389b5d1c0476e315736df31562328894Doris Liu        mModeCoverState = COVER_SHOWN;
1557e038c161389b5d1c0476e315736df31562328894Doris Liu
1558e038c161389b5d1c0476e315736df31562328894Doris Liu        int lastIndex = mController.getCurrentModuleIndex();
15590496fcaa51f88f6c753975473b971941e4090cfaSpike Sprague        // Actual mode teardown / new mode initialization happens here
1560e038c161389b5d1c0476e315736df31562328894Doris Liu        mController.onModeSelected(modeIndex);
1561e038c161389b5d1c0476e315736df31562328894Doris Liu        int currentIndex = mController.getCurrentModuleIndex();
1562b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu
1563d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        if (lastIndex == currentIndex) {
1564b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu            hideModeCover();
1565b6eaa8c70da19fb3233c3c4b1a2625ce90fc35afDoris Liu        }
1566d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
1567d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        updateModeSpecificUIColors();
1568d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
1569d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
1570d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private void updateModeSpecificUIColors() {
1571d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        setBottomBarColorsForModeIndex(mController.getCurrentModuleIndex());
1572f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
1573f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
1574213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu    @Override
15759d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    public void onSettingsSelected() {
15766190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren        mController.getSettingsManager().set(SettingsManager.SCOPE_GLOBAL,
15776190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren                                             Keys.KEY_SHOULD_SHOW_SETTINGS_BUTTON_CLING, false);
157826aa92bf5942bfde16621c6833c14ba0e1ea8b5eDoris Liu        mModeListView.setShouldShowSettingsCling(false);
15799d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu        mController.onSettingsSelected();
15809d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    }
15819d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu
15829d264309a341c52601bdccdeff6647e0ce58c31fDoris Liu    @Override
1583213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu    public int getCurrentModeIndex() {
1584213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu        return mController.getCurrentModuleIndex();
1585213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu    }
1586213a4a086b54904cee543adf60b16fc1a61efe38Doris Liu
1587f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    /********************** Capture animation **********************/
1588f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    /* TODO: This session is subject to UX changes. In addition to the generic
1589f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu       flash animation and post capture animation, consider designating a parameter
1590f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu       for specifying the type of animation, as well as an animation finished listener
1591f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu       so that modules can have more knowledge of the status of the animation. */
1592f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
1593f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    /**
1594ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu     * Turns on or off the capture indicator suppression.
1595ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu     */
1596ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu    public void setShouldSuppressCaptureIndicator(boolean suppress) {
1597ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu        mSuppressCaptureIndicator = suppress;
1598ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu    }
1599ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu
1600ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu    /**
1601427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu     * Starts the capture indicator pop-out animation.
16025052117cc429d85cf446421ca74859f4365747d3Angus Kong     *
1603427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu     * @param accessibilityString An accessibility String to be announced during the peek animation.
16045052117cc429d85cf446421ca74859f4365747d3Angus Kong     */
1605427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    public void startCaptureIndicatorRevealAnimation(String accessibilityString) {
1606ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu        if (mSuppressCaptureIndicator || mFilmstripLayout.getVisibility() == View.VISIBLE) {
16075052117cc429d85cf446421ca74859f4365747d3Angus Kong            return;
16085052117cc429d85cf446421ca74859f4365747d3Angus Kong        }
1609427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        mRoundedThumbnailView.startRevealThumbnailAnimation(accessibilityString);
16105052117cc429d85cf446421ca74859f4365747d3Angus Kong    }
16115052117cc429d85cf446421ca74859f4365747d3Angus Kong
16125052117cc429d85cf446421ca74859f4365747d3Angus Kong    /**
1613427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu     * Updates the thumbnail image in the capture indicator.
161417d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers     *
1615427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu     * @param thumbnailBitmap The thumbnail image to be shown.
1616427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu     */
16173830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling    public void updateCaptureIndicatorThumbnail(Bitmap thumbnailBitmap, int rotation) {
1618ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu        if (mSuppressCaptureIndicator || mFilmstripLayout.getVisibility() == View.VISIBLE) {
1619ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu            return;
1620ecb546aca4093beb60a3d40171b5038693dc7d05Senpo Hu        }
162104aab100674dfdd11bffabc46e6a199f5e9a5267Paul Rohde        mRoundedThumbnailView.setThumbnail(thumbnailBitmap, rotation);
1622427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    }
1623427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu
1624427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    /**
1625427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu     * Hides the capture indicator.
1626427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu     */
1627427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    public void hideCaptureIndicator() {
1628427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        mRoundedThumbnailView.hideThumbnail();
1629427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    }
1630427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu
1631427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    /**
1632427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu     * Starts the flash animation.
1633f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     */
1634427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu    public void startFlashAnimation(boolean shortFlash) {
163517d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers        mCaptureOverlay.startFlashAnimation(shortFlash);
1636f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
1637f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
1638f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    /**
1639f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * Cancels the pre-capture animation.
1640f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     */
1641f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    public void cancelPreCaptureAnimation() {
1642f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mAnimationManager.cancelAnimations();
1643f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
1644f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu
1645f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    /**
1646f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     * Cancels the post-capture animation.
1647f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu     */
1648f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    public void cancelPostCaptureAnimation() {
1649f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mAnimationManager.cancelAnimations();
1650f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
165106db742814dd635d100639f977fcfdc904deb778Doris Liu
1652b2510252fb020f3ccb88787c870930427377b9dfAngus Kong    public FilmstripContentPanel getFilmstripContentPanel() {
1653b2510252fb020f3ccb88787c870930427377b9dfAngus Kong        return mFilmstripPanel;
1654b2510252fb020f3ccb88787c870930427377b9dfAngus Kong    }
1655b2510252fb020f3ccb88787c870930427377b9dfAngus Kong
1656b2510252fb020f3ccb88787c870930427377b9dfAngus Kong    /**
16577ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong     * @return The {@link com.android.camera.app.CameraAppUI.BottomPanel} on the
1658b2510252fb020f3ccb88787c870930427377b9dfAngus Kong     * bottom of the filmstrip.
1659b2510252fb020f3ccb88787c870930427377b9dfAngus Kong     */
16607ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong    public BottomPanel getFilmstripBottomControls() {
1661e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        return mFilmstripBottomControls;
1662b2510252fb020f3ccb88787c870930427377b9dfAngus Kong    }
1663b2510252fb020f3ccb88787c870930427377b9dfAngus Kong
1664ba97d192b63ea81edf2dd6ca5cfbf6646a1f25a2Spike Sprague    public void showBottomControls() {
1665ba97d192b63ea81edf2dd6ca5cfbf6646a1f25a2Spike Sprague        mFilmstripBottomControls.show();
1666ba97d192b63ea81edf2dd6ca5cfbf6646a1f25a2Spike Sprague    }
1667ba97d192b63ea81edf2dd6ca5cfbf6646a1f25a2Spike Sprague
1668ba97d192b63ea81edf2dd6ca5cfbf6646a1f25a2Spike Sprague    public void hideBottomControls() {
1669ba97d192b63ea81edf2dd6ca5cfbf6646a1f25a2Spike Sprague        mFilmstripBottomControls.hide();
1670ba97d192b63ea81edf2dd6ca5cfbf6646a1f25a2Spike Sprague    }
1671ba97d192b63ea81edf2dd6ca5cfbf6646a1f25a2Spike Sprague
1672b2510252fb020f3ccb88787c870930427377b9dfAngus Kong    /**
1673b2510252fb020f3ccb88787c870930427377b9dfAngus Kong     * @param listener The listener for bottom controls.
1674b2510252fb020f3ccb88787c870930427377b9dfAngus Kong     */
16757ae25c21fefd8b7fd4c4e1c207631f751167cb0aAngus Kong    public void setFilmstripBottomControlsListener(BottomPanel.Listener listener) {
1676e0aff89f3e05eb6008651b290ba79d484de55970Angus Kong        mFilmstripBottomControls.setListener(listener);
1677b2510252fb020f3ccb88787c870930427377b9dfAngus Kong    }
1678b2510252fb020f3ccb88787c870930427377b9dfAngus Kong
1679d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /***************************SurfaceTexture Api and Listener*********************************/
1680d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1681d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /**
1682d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * Return the shared surface texture.
1683d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     */
1684d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public SurfaceTexture getSurfaceTexture() {
1685d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        return mSurface;
1686d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
1687d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1688d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /**
1689d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * Return the shared {@link android.graphics.SurfaceTexture}'s width.
1690d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     */
1691d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public int getSurfaceWidth() {
1692d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        return mSurfaceWidth;
1693d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
1694d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1695d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /**
1696d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * Return the shared {@link android.graphics.SurfaceTexture}'s height.
1697d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     */
1698d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public int getSurfaceHeight() {
1699d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        return mSurfaceHeight;
1700d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
170106db742814dd635d100639f977fcfdc904deb778Doris Liu
170206db742814dd635d100639f977fcfdc904deb778Doris Liu    @Override
170306db742814dd635d100639f977fcfdc904deb778Doris Liu    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
1704d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mSurface = surface;
1705d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mSurfaceWidth = width;
1706d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mSurfaceHeight = height;
17072b906b8c9754b564d5113c7a342654c82f97f180Doris Liu        Log.v(TAG, "SurfaceTexture is available");
170806db742814dd635d100639f977fcfdc904deb778Doris Liu        if (mPreviewStatusListener != null) {
170906db742814dd635d100639f977fcfdc904deb778Doris Liu            mPreviewStatusListener.onSurfaceTextureAvailable(surface, width, height);
171006db742814dd635d100639f977fcfdc904deb778Doris Liu        }
1711a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren        enableModeOptions();
171206db742814dd635d100639f977fcfdc904deb778Doris Liu    }
171306db742814dd635d100639f977fcfdc904deb778Doris Liu
171406db742814dd635d100639f977fcfdc904deb778Doris Liu    @Override
171506db742814dd635d100639f977fcfdc904deb778Doris Liu    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
1716d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mSurface = surface;
1717d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mSurfaceWidth = width;
1718d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mSurfaceHeight = height;
171906db742814dd635d100639f977fcfdc904deb778Doris Liu        if (mPreviewStatusListener != null) {
172006db742814dd635d100639f977fcfdc904deb778Doris Liu            mPreviewStatusListener.onSurfaceTextureSizeChanged(surface, width, height);
172106db742814dd635d100639f977fcfdc904deb778Doris Liu        }
172206db742814dd635d100639f977fcfdc904deb778Doris Liu    }
172306db742814dd635d100639f977fcfdc904deb778Doris Liu
172406db742814dd635d100639f977fcfdc904deb778Doris Liu    @Override
172506db742814dd635d100639f977fcfdc904deb778Doris Liu    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
1726d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mSurface = null;
17272b906b8c9754b564d5113c7a342654c82f97f180Doris Liu        Log.v(TAG, "SurfaceTexture is destroyed");
172806db742814dd635d100639f977fcfdc904deb778Doris Liu        if (mPreviewStatusListener != null) {
172906db742814dd635d100639f977fcfdc904deb778Doris Liu            return mPreviewStatusListener.onSurfaceTextureDestroyed(surface);
173006db742814dd635d100639f977fcfdc904deb778Doris Liu        }
173106db742814dd635d100639f977fcfdc904deb778Doris Liu        return false;
173206db742814dd635d100639f977fcfdc904deb778Doris Liu    }
173306db742814dd635d100639f977fcfdc904deb778Doris Liu
173406db742814dd635d100639f977fcfdc904deb778Doris Liu    @Override
173506db742814dd635d100639f977fcfdc904deb778Doris Liu    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
1736d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mSurface = surface;
17373c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague        if (mPreviewStatusListener != null) {
17383c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague            mPreviewStatusListener.onSurfaceTextureUpdated(surface);
17393c3b31dfd5ec7a43e89cd4695cc8c498afc3a91dSpike Sprague        }
17407e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin        // Do not show the first preview frame. Due to the bug b/20724126, we need to have
17417e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin        // a WAR to request a preview frame followed by 5-frame ZSL burst before the repeating
17427e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin        // preview and ZSL streams. Need to hide the first preview frame since it is janky.
17437e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin        // We do this only for L, Nexus 6 and Haleakala.
17447e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin        if (mModeCoverState == COVER_WILL_HIDE_AFTER_NEXT_TEXTURE_UPDATE) {
17457e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin            mModeCoverState = COVER_WILL_HIDE_AT_NEXT_TEXTURE_UPDATE;
17467e39f8b015985fc0e539e14c193286065b5e51d4Pengchong Jin        } else if (mModeCoverState == COVER_WILL_HIDE_AT_NEXT_TEXTURE_UPDATE){
1747c91c8d273b8884468dfd66a5b82526dc8245934eAlan Newberger            Log.v(TAG, "hiding cover via onSurfaceTextureUpdated");
17487cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu            CameraPerformanceTracker.onEvent(CameraPerformanceTracker.FIRST_PREVIEW_FRAME);
17492b906b8c9754b564d5113c7a342654c82f97f180Doris Liu            hideModeCover();
175006db742814dd635d100639f977fcfdc904deb778Doris Liu        }
175106db742814dd635d100639f977fcfdc904deb778Doris Liu    }
17524efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
1753b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren    /****************************Grid lines api ******************************/
1754b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren
1755b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren    /**
1756b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren     * Show a set of evenly spaced lines over the preview.  The number
1757b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren     * of lines horizontally and vertically is determined by
1758b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren     * {@link com.android.camera.ui.GridLines}.
1759b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren     */
1760b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren    public void showGridLines() {
1761b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren        if (mGridLines != null) {
1762b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren            mGridLines.setVisibility(View.VISIBLE);
1763b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren        }
1764b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren    }
1765b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren
1766b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren    /**
1767b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren     * Hide the set of evenly spaced grid lines overlaying the preview.
1768b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren     */
1769b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren    public void hideGridLines() {
1770b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren        if (mGridLines != null) {
1771b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren            mGridLines.setVisibility(View.INVISIBLE);
1772b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren        }
1773b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren    }
1774b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren
1775d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren    /**
1776d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren     * Return a callback which shows or hide the preview grid lines
1777d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren     * depending on whether the grid lines setting is set on.
1778d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren     */
1779d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren    public ButtonManager.ButtonCallback getGridLinesCallback() {
1780d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        return new ButtonManager.ButtonCallback() {
1781d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren            @Override
1782d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren            public void onStateChanged(int state) {
17832356bd78cfeb51977845155b580104ce959083f2Alan Newberger                if (!mController.isPaused()) {
17842356bd78cfeb51977845155b580104ce959083f2Alan Newberger                    if (Keys.areGridLinesOn(mController.getSettingsManager())) {
17852356bd78cfeb51977845155b580104ce959083f2Alan Newberger                        showGridLines();
17862356bd78cfeb51977845155b580104ce959083f2Alan Newberger                    } else {
17872356bd78cfeb51977845155b580104ce959083f2Alan Newberger                        hideGridLines();
17882356bd78cfeb51977845155b580104ce959083f2Alan Newberger                    }
1789d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren                }
1790d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren            }
1791d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        };
1792d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren    }
1793d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren
1794d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /***************************Mode options api *****************************/
1795d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1796d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /**
1797d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * Set the mode options visible.
1798d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     */
1799d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public void showModeOptions() {
1800a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren        /* Make mode options clickable. */
1801a7919c720c49d7aa9a033366a92f8b1828619a0fErin Dahlgren        enableModeOptions();
1802d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mModeOptionsOverlay.setVisibility(View.VISIBLE);
1803d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
1804d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1805d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /**
1806d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * Set the mode options invisible.  This is necessary for modes
1807d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * that don't show a bottom bar for the capture UI.
1808d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     */
1809d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public void hideModeOptions() {
1810d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mModeOptionsOverlay.setVisibility(View.INVISIBLE);
1811d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
1812b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren
1813b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren    /****************************Bottom bar api ******************************/
1814b3f59a874f675ceb7542298760a3c813c5e0d9acErin Dahlgren
18154efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
1816d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * Sets up the bottom bar and mode options with the correct
1817d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * shutter button and visibility based on the current module.
1818d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     */
1819d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public void resetBottomControls(ModuleController module, int moduleIndex) {
1820d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        if (areBottomControlsUsed(module)) {
1821d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            setBottomBarShutterIcon(moduleIndex);
1822344320c90639f823451ddac42e8f39b74727787cDoris Liu            mCaptureLayoutHelper.setShowBottomBar(true);
1823344320c90639f823451ddac42e8f39b74727787cDoris Liu        } else {
1824344320c90639f823451ddac42e8f39b74727787cDoris Liu            mCaptureLayoutHelper.setShowBottomBar(false);
1825d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        }
1826d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
1827d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1828d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /**
1829d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * Show or hide the mode options and bottom bar, based on
1830d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * whether the current module is using the bottom bar.  Returns
1831d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * whether the mode options and bottom bar are used.
1832d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     */
1833d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    private boolean areBottomControlsUsed(ModuleController module) {
1834d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        if (module.isUsingBottomBar()) {
1835d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            showBottomBar();
1836d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            showModeOptions();
1837d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            return true;
1838d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        } else {
1839d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            hideBottomBar();
1840d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            hideModeOptions();
1841d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            return false;
1842d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        }
1843d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
1844d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1845d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /**
1846d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * Set the bottom bar visible.
1847d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     */
1848d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public void showBottomBar() {
1849d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mBottomBar.setVisibility(View.VISIBLE);
1850d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
1851d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1852d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /**
1853d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * Set the bottom bar invisible.
1854d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     */
1855d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public void hideBottomBar() {
1856d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mBottomBar.setVisibility(View.INVISIBLE);
1857d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
1858d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1859d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /**
18604efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Sets the color of the bottom bar.
18614efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
18624efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    public void setBottomBarColor(int colorId) {
18634efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mBottomBar.setBackgroundColor(colorId);
18644efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
18654efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
18664efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
1867d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague     * Sets the pressed color of the bottom bar for a camera mode index.
1868b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague     */
1869d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    public void setBottomBarColorsForModeIndex(int index) {
1870d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        mBottomBar.setColorsForModeIndex(index);
1871b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    }
1872b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague
1873b92910e04c4da91fc4ea5a9484b83f9ecba1c896Spike Sprague    /**
1874d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * Sets the shutter button icon on the bottom bar, based on
1875d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * the mode index.
187639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague     */
1877d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public void setBottomBarShutterIcon(int modeIndex) {
1878d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        int shutterIconId = CameraUtil.getCameraShutterIconId(modeIndex,
1879d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            mController.getAndroidContext());
1880fecd723c1cfd90332cd2805be79a24f26643ebb9Erin Dahlgren        mBottomBar.setShutterButtonIcon(shutterIconId);
188139f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
188239f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
188345a821d43ae8d7287b649f670a66ab3d99eeccafSpike Sprague    public void animateBottomBarToVideoStop(int shutterIconId) {
188445a821d43ae8d7287b649f670a66ab3d99eeccafSpike Sprague        mBottomBar.animateToVideoStop(shutterIconId);
188539f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
188639f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
1887fecd723c1cfd90332cd2805be79a24f26643ebb9Erin Dahlgren    public void animateBottomBarToFullSize(int shutterIconId) {
1888fecd723c1cfd90332cd2805be79a24f26643ebb9Erin Dahlgren        mBottomBar.animateToFullSize(shutterIconId);
188939f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    }
189039f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague
18910cf4a02c13a7710dc9b26ac39bea15a95ac48bafSascha Haeberling    public void setShutterButtonEnabled(final boolean enabled) {
1892d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague        if (!mDisableAllUserInteractions) {
1893d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague            mBottomBar.post(new Runnable() {
1894d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague                @Override
1895d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague                public void run() {
1896d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague                    mBottomBar.setShutterButtonEnabled(enabled);
1897d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague                }
1898d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague            });
1899d2d8b711c14ee47f6f4ea16cb9fe27128462ad5bSpike Sprague        }
1900667630d16a2b0cf3acecb817b3aa398abdd33623Erin Dahlgren    }
1901667630d16a2b0cf3acecb817b3aa398abdd33623Erin Dahlgren
1902b7e41a734a9cf9b5789fd3221ba10833f669b7c5Spike Sprague    public void setShutterButtonImportantToA11y(boolean important) {
1903b7e41a734a9cf9b5789fd3221ba10833f669b7c5Spike Sprague        mBottomBar.setShutterButtonImportantToA11y(important);
1904b7e41a734a9cf9b5789fd3221ba10833f669b7c5Spike Sprague    }
1905b7e41a734a9cf9b5789fd3221ba10833f669b7c5Spike Sprague
1906667630d16a2b0cf3acecb817b3aa398abdd33623Erin Dahlgren    public boolean isShutterButtonEnabled() {
1907667630d16a2b0cf3acecb817b3aa398abdd33623Erin Dahlgren        return mBottomBar.isShutterButtonEnabled();
1908a93909ffe93c9f5e27e493f32a78aab6fbf3e06eSpike Sprague    }
1909a93909ffe93c9f5e27e493f32a78aab6fbf3e06eSpike Sprague
1910b6db6917db367e4ca0992ca8614a4cfc59d68d92Alan Newberger    public void setIndicatorBottomBarWrapperVisible(boolean visible) {
1911427a915be4bcc84fa1c32d9e9e1b7473c522f732Senpo Hu        mStickyBottomCaptureLayout.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
1912f495ea8ca078fc752b1ed1045ba22817d75e968eAlan Newberger    }
1913f495ea8ca078fc752b1ed1045ba22817d75e968eAlan Newberger
191439f8a7647aa4051a1c260b9496c2db82f93f8667Spike Sprague    /**
19154efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Set the visibility of the bottom bar.
19164efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
19174efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    // TODO: needed for when panorama is managed by the generic module ui.
19184efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    public void setBottomBarVisible(boolean visible) {
19194efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mBottomBar.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
19204efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
19214efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
19224efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
19235d18769f53db81d401488811250570290a73626bErin Dahlgren     * Add a {@link #ShutterButton.OnShutterButtonListener} to the shutter button.
19244efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
19255d18769f53db81d401488811250570290a73626bErin Dahlgren    public void addShutterListener(ShutterButton.OnShutterButtonListener listener) {
19265d18769f53db81d401488811250570290a73626bErin Dahlgren        mShutterButton.addOnShutterButtonListener(listener);
19275d18769f53db81d401488811250570290a73626bErin Dahlgren    }
19285d18769f53db81d401488811250570290a73626bErin Dahlgren
19295d18769f53db81d401488811250570290a73626bErin Dahlgren    /**
19305d18769f53db81d401488811250570290a73626bErin Dahlgren     * Remove a {@link #ShutterButton.OnShutterButtonListener} from the shutter button.
19315d18769f53db81d401488811250570290a73626bErin Dahlgren     */
19325d18769f53db81d401488811250570290a73626bErin Dahlgren    public void removeShutterListener(ShutterButton.OnShutterButtonListener listener) {
19335d18769f53db81d401488811250570290a73626bErin Dahlgren        mShutterButton.removeOnShutterButtonListener(listener);
19344efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
19354efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
19364efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
193764d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling     * Sets or replaces the "cancel shutter" button listener.
193864d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling     * <p>
193964d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling     * TODO: Make this part of the interface the same way shutter button
194064d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling     * listeners are.
194164d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling     */
194264d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling    public void setCancelShutterButtonListener(View.OnClickListener listener) {
194364d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling        mCountdownCancelButton.setOnClickListener(listener);
194464d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling    }
194564d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling
194664d22d9caf0824739cb250575d69a56fe7f3fa3cSascha Haeberling    /**
1947d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     * Performs a transition to the capture layout of the bottom bar.
1948d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren     */
1949d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public void transitionToCapture() {
1950d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        ModuleController moduleController = mController.getCurrentModuleController();
1951d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        applyModuleSpecs(moduleController.getHardwareSpec(),
1952d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            moduleController.getBottomBarSpec());
1953d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mBottomBar.transitionToCapture();
1954d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
1955d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
1956d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    /**
19572db51d761f8fb070f660b90913e131ab361cbbadSeth Raphael     * Displays the Cancel button instead of the capture button.
19582db51d761f8fb070f660b90913e131ab361cbbadSeth Raphael     */
19592db51d761f8fb070f660b90913e131ab361cbbadSeth Raphael    public void transitionToCancel() {
19602db51d761f8fb070f660b90913e131ab361cbbadSeth Raphael        ModuleController moduleController = mController.getCurrentModuleController();
19612db51d761f8fb070f660b90913e131ab361cbbadSeth Raphael        applyModuleSpecs(moduleController.getHardwareSpec(),
19622db51d761f8fb070f660b90913e131ab361cbbadSeth Raphael                moduleController.getBottomBarSpec());
19632db51d761f8fb070f660b90913e131ab361cbbadSeth Raphael        mBottomBar.transitionToCancel();
19642db51d761f8fb070f660b90913e131ab361cbbadSeth Raphael    }
19652db51d761f8fb070f660b90913e131ab361cbbadSeth Raphael
19662db51d761f8fb070f660b90913e131ab361cbbadSeth Raphael    /**
19674efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Performs a transition to the global intent layout.
19684efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
196915690d02da08bda74ed63f260b70076801bf91bfSpike Sprague    public void transitionToIntentCaptureLayout() {
1970b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        ModuleController moduleController = mController.getCurrentModuleController();
1971d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        applyModuleSpecs(moduleController.getHardwareSpec(),
1972d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            moduleController.getBottomBarSpec());
197315690d02da08bda74ed63f260b70076801bf91bfSpike Sprague        mBottomBar.transitionToIntentCaptureLayout();
1974b45f618d4a3aa068766be8741213080532feaaffSpike Sprague        showModeOptions();
19754efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
19764efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
19774efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    /**
19784efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     * Performs a transition to the global intent review layout.
19794efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren     */
19804efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    public void transitionToIntentReviewLayout() {
1981b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        ModuleController moduleController = mController.getCurrentModuleController();
1982d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        applyModuleSpecs(moduleController.getHardwareSpec(),
1983d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren            moduleController.getBottomBarSpec());
1984d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mBottomBar.transitionToIntentReviewLayout();
1985b45f618d4a3aa068766be8741213080532feaaffSpike Sprague        hideModeOptions();
1986e5c19b4acc3be9b70e665627f76d082c6fc3289dSenpo Hu
1987e5c19b4acc3be9b70e665627f76d082c6fc3289dSenpo Hu        // Hide the preview snapshot since the screen is frozen when users tap
1988e5c19b4acc3be9b70e665627f76d082c6fc3289dSenpo Hu        // shutter button in capture intent.
1989e5c19b4acc3be9b70e665627f76d082c6fc3289dSenpo Hu        hideModeCover();
1990b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren    }
1991b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
19929f3d01d9c5d2200882de76e309db55d74d950110Spike Sprague    /**
19939f3d01d9c5d2200882de76e309db55d74d950110Spike Sprague     * @return whether UI is in intent review mode
19949f3d01d9c5d2200882de76e309db55d74d950110Spike Sprague     */
19959f3d01d9c5d2200882de76e309db55d74d950110Spike Sprague    public boolean isInIntentReview() {
19969f3d01d9c5d2200882de76e309db55d74d950110Spike Sprague        return mBottomBar.isInIntentReview();
19979f3d01d9c5d2200882de76e309db55d74d950110Spike Sprague    }
19989f3d01d9c5d2200882de76e309db55d74d950110Spike Sprague
19993c62221afd869828ba867fce15755a582f2c2334Erin Dahlgren    @Override
20006190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren    public void onSettingChanged(SettingsManager settingsManager, String key) {
20013c62221afd869828ba867fce15755a582f2c2334Erin Dahlgren        // Update the mode options based on the hardware spec,
20023c62221afd869828ba867fce15755a582f2c2334Erin Dahlgren        // when hdr changes to prevent flash from getting out of sync.
20036190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren        if (key.equals(Keys.KEY_CAMERA_HDR)) {
20043c62221afd869828ba867fce15755a582f2c2334Erin Dahlgren            ModuleController moduleController = mController.getCurrentModuleController();
20053c62221afd869828ba867fce15755a582f2c2334Erin Dahlgren            applyModuleSpecs(moduleController.getHardwareSpec(),
2006ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                             moduleController.getBottomBarSpec(),
2007ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                             true /*skipScopeCheck*/);
20083c62221afd869828ba867fce15755a582f2c2334Erin Dahlgren        }
20093c62221afd869828ba867fce15755a582f2c2334Erin Dahlgren    }
20103c62221afd869828ba867fce15755a582f2c2334Erin Dahlgren
2011b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren    /**
2012b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * Applies a {@link com.android.camera.CameraAppUI.BottomBarUISpec}
2013b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * to the bottom bar mode options based on limitations from a
2014b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * {@link com.android.camera.hardware.HardwareSpec}.
2015b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     *
2016b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * Options not supported by the hardware are either hidden
2017b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * or disabled, depending on the option.
2018b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     *
2019b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     * Otherwise, the option is fully enabled and clickable.
2020b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren     */
2021ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava    public void applyModuleSpecs(HardwareSpec hardwareSpec,
2022ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            BottomBarUISpec bottomBarSpec) {
2023ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava        applyModuleSpecs(hardwareSpec, bottomBarSpec, false /*skipScopeCheck*/);
2024ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava    }
2025ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava
2026ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava    private void applyModuleSpecs(final HardwareSpec hardwareSpec,
2027ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava           final BottomBarUISpec bottomBarSpec, boolean skipScopeCheck) {
202849ab922e8e1e7535286392fc667312ec419403fdErin Dahlgren        if (hardwareSpec == null || bottomBarSpec == null) {
202949ab922e8e1e7535286392fc667312ec419403fdErin Dahlgren            return;
2030b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        }
2031b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
2032b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        ButtonManager buttonManager = mController.getButtonManager();
2033b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        SettingsManager settingsManager = mController.getSettingsManager();
2034b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
203559345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague        buttonManager.setToInitialState();
203659345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague
2037ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava        if (skipScopeCheck
2038ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                || !mController.getModuleScope().equals(mCurrentModuleScope)
2039ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                || !mController.getCameraScope().equals(mCurrentCameraScope)) {
2040ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava
2041ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            // Scope dependent options, update only if the module or the
2042ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            // camera scope changed or scope-check skip was requested.
2043ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            mCurrentModuleScope = mController.getModuleScope();
2044ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            mCurrentCameraScope = mController.getCameraScope();
2045ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava
20464368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava            mHdrSupportMode = settingsManager.getString(SettingsManager.SCOPE_GLOBAL,
20474368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                    Keys.KEY_HDR_SUPPORT_MODE_BACK_CAMERA);
20489a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava
2049ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            /** Standard mode options */
2050ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            if (mController.getCameraProvider().getNumberOfCameras() > 1 &&
2051ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    hardwareSpec.isFrontCameraSupported()) {
2052ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                if (bottomBarSpec.enableCamera) {
20534368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                    int hdrButtonId = ButtonManager.BUTTON_HDR;
20544368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                    if (mHdrSupportMode.equals(getResourceString(
20554368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                            R.string.pref_camera_hdr_supportmode_hdr_plus))) {
20564368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                        hdrButtonId = ButtonManager.BUTTON_HDR_PLUS;
20574368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                    }
2058ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    buttonManager.initializeButton(ButtonManager.BUTTON_CAMERA,
20599a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava                            bottomBarSpec.cameraCallback,
20604368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                            getDisableButtonCallback(hdrButtonId));
2061ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                } else {
2062ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    buttonManager.disableButton(ButtonManager.BUTTON_CAMERA);
2063ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                }
2064b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren            } else {
2065ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                // Hide camera icon if front camera not available.
2066ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                buttonManager.hideButton(ButtonManager.BUTTON_CAMERA);
2067b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren            }
2068b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
2069ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            boolean flashBackCamera = settingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL,
2070ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    Keys.KEY_FLASH_SUPPORTED_BACK_CAMERA);
2071ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            if (bottomBarSpec.hideFlash
2072ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    || !flashBackCamera) {
2073ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                // Hide both flash and torch button in flash disable logic
2074ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                buttonManager.hideButton(ButtonManager.BUTTON_FLASH);
2075ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                buttonManager.hideButton(ButtonManager.BUTTON_TORCH);
2076b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren            } else {
2077ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                if (hardwareSpec.isFlashSupported()) {
2078ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    if (bottomBarSpec.enableFlash) {
2079ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        buttonManager.initializeButton(ButtonManager.BUTTON_FLASH,
2080ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                                bottomBarSpec.flashCallback);
2081ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    } else if (bottomBarSpec.enableTorchFlash) {
2082ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        buttonManager.initializeButton(ButtonManager.BUTTON_TORCH,
2083ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                                bottomBarSpec.flashCallback);
2084ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    } else if (bottomBarSpec.enableHdrPlusFlash) {
2085ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        buttonManager.initializeButton(ButtonManager.BUTTON_HDR_PLUS_FLASH,
2086ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                                bottomBarSpec.flashCallback);
2087ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    } else {
2088ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        // Disable both flash and torch button in flash disable
2089ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        // logic. Need to ensure it's visible, it may be hidden
2090ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        // from previous non-flash mode.
2091ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        buttonManager.showButton(ButtonManager.BUTTON_FLASH);
2092ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        buttonManager.disableButton(ButtonManager.BUTTON_FLASH);
2093ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        buttonManager.disableButton(ButtonManager.BUTTON_TORCH);
2094ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    }
2095b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren                } else {
2096ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    // Flash not supported but another module does.
2097ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    // Disable flash button. Need to ensure it's visible,
2098ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    // it may be hidden from previous non-flash mode.
2099ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    buttonManager.showButton(ButtonManager.BUTTON_FLASH);
2100ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    buttonManager.disableButton(ButtonManager.BUTTON_FLASH);
2101ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    buttonManager.disableButton(ButtonManager.BUTTON_TORCH);
2102b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren                }
2103ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            }
2104ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava
2105ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            if (bottomBarSpec.hideHdr || mIsCaptureIntent) {
2106ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                // Force hide hdr or hdr plus icon.
2107ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                buttonManager.hideButton(ButtonManager.BUTTON_HDR_PLUS);
2108ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava            } else {
2109ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                if (hardwareSpec.isHdrPlusSupported()) {
21104368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                    mHdrSupportMode = getResourceString(
21114368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                            R.string.pref_camera_hdr_supportmode_hdr_plus);
2112ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    if (bottomBarSpec.enableHdr) {
2113ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        buttonManager.initializeButton(ButtonManager.BUTTON_HDR_PLUS,
21149a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava                                bottomBarSpec.hdrCallback,
21159a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava                                getDisableButtonCallback(ButtonManager.BUTTON_CAMERA));
2116ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    } else {
2117ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        buttonManager.disableButton(ButtonManager.BUTTON_HDR_PLUS);
2118ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    }
2119ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                } else if (hardwareSpec.isHdrSupported()) {
21204368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                    mHdrSupportMode = getResourceString(R.string.pref_camera_hdr_supportmode_hdr);
2121ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    if (bottomBarSpec.enableHdr) {
2122ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        buttonManager.initializeButton(ButtonManager.BUTTON_HDR,
21239a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava                                bottomBarSpec.hdrCallback,
21249a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava                                getDisableButtonCallback(ButtonManager.BUTTON_CAMERA));
2125ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    } else {
2126ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        buttonManager.disableButton(ButtonManager.BUTTON_HDR);
2127ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    }
2128b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren                } else {
2129ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    // Hide hdr plus or hdr icon if neither are supported overall.
21304368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                    if (mHdrSupportMode.isEmpty() || mHdrSupportMode
21314368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                            .equals(getResourceString(R.string.pref_camera_hdr_supportmode_none))) {
2132ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        buttonManager.hideButton(ButtonManager.BUTTON_HDR_PLUS);
2133ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    } else {
2134ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        // Disable HDR button. Need to ensure it's visible,
2135ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                        // it may be hidden from previous non HDR mode (eg. Video).
21364368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                        int buttonId = ButtonManager.BUTTON_HDR;
21374368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                        if (mHdrSupportMode.equals(
21384368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                                getResourceString(R.string.pref_camera_hdr_supportmode_hdr_plus))) {
21394368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                            buttonId = ButtonManager.BUTTON_HDR_PLUS;
21404368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                        }
21414368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                        buttonManager.showButton(buttonId);
21424368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava                        buttonManager.disableButton(buttonId);
2143ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava                    }
2144b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren                }
2145b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren            }
2146b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren
2147ce9ef4e3528e5599773809f74657b798c370aad2Gabriel Nava        }
2148d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        if (bottomBarSpec.hideGridLines) {
2149d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren            // Force hide grid lines icon.
2150d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren            buttonManager.hideButton(ButtonManager.BUTTON_GRID_LINES);
2151d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren            hideGridLines();
2152d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        } else {
2153d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren            if (bottomBarSpec.enableGridLines) {
21548ad8ad4841f65ee89e3c5e79f57d95cf8e4438b4Doris Liu                buttonManager.initializeButton(ButtonManager.BUTTON_GRID_LINES,
21558ad8ad4841f65ee89e3c5e79f57d95cf8e4438b4Doris Liu                        bottomBarSpec.gridLinesCallback != null ?
21568ad8ad4841f65ee89e3c5e79f57d95cf8e4438b4Doris Liu                                bottomBarSpec.gridLinesCallback : getGridLinesCallback()
21578ad8ad4841f65ee89e3c5e79f57d95cf8e4438b4Doris Liu                );
2158d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren            } else {
2159d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren                buttonManager.disableButton(ButtonManager.BUTTON_GRID_LINES);
2160d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren                hideGridLines();
2161d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren            }
2162d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren        }
2163d5e51466a2848f1c937656c8f8185290034c2429Erin Dahlgren
21646c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        if (bottomBarSpec.enableSelfTimer) {
21656c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu            buttonManager.initializeButton(ButtonManager.BUTTON_COUNTDOWN, null);
21666c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        } else {
21674333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling            if (bottomBarSpec.showSelfTimer) {
21684333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling                buttonManager.disableButton(ButtonManager.BUTTON_COUNTDOWN);
21694333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling            } else {
21704333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling                buttonManager.hideButton(ButtonManager.BUTTON_COUNTDOWN);
21714333fac867f6f6a11235b16d305dd197093b44d5Sascha Haeberling            }
21726c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        }
21736c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
2174f80ac9ee5c66671c3a77ac6628fefc86cd39d57eErin Dahlgren        if (bottomBarSpec.enablePanoOrientation
2175f80ac9ee5c66671c3a77ac6628fefc86cd39d57eErin Dahlgren                && PhotoSphereHelper.getPanoramaOrientationOptionArrayId() > 0) {
217659345144c4bde59b81bb19c95cdd977c1d1a9cd4Spike Sprague            buttonManager.initializePanoOrientationButtons(bottomBarSpec.panoOrientationCallback);
2177a1fab413bcbe5f62ae1d829bac0539519fef96a6Erin Dahlgren        }
2178a1fab413bcbe5f62ae1d829bac0539519fef96a6Erin Dahlgren
217957c889d4b88517dd0996547dbae4f314c2a3fcdfzafir
218057c889d4b88517dd0996547dbae4f314c2a3fcdfzafir
218157c889d4b88517dd0996547dbae4f314c2a3fcdfzafir        // If manual exposure is enabled both in SettingsManager and
218257c889d4b88517dd0996547dbae4f314c2a3fcdfzafir        // BottomBarSpec,then show the exposure button.
218357c889d4b88517dd0996547dbae4f314c2a3fcdfzafir        // If manual exposure is disabled in the BottomBarSpec (eg. HDR+
21846ffdeac1670c8938d0331c89d9269b68f361d6fazafir        // enabled), but the device/module has the feature, then disable the exposure
218557c889d4b88517dd0996547dbae4f314c2a3fcdfzafir        // button.
218657c889d4b88517dd0996547dbae4f314c2a3fcdfzafir        // Otherwise, hide the button.
21870409c8594fd1629ee07df827cf0d7a0f336b9326zafir        if (bottomBarSpec.enableExposureCompensation
21880409c8594fd1629ee07df827cf0d7a0f336b9326zafir                && !(bottomBarSpec.minExposureCompensation == 0 && bottomBarSpec.maxExposureCompensation == 0)
21890409c8594fd1629ee07df827cf0d7a0f336b9326zafir                && mController.getSettingsManager().getBoolean(SettingsManager.SCOPE_GLOBAL,
21900409c8594fd1629ee07df827cf0d7a0f336b9326zafir                        Keys.KEY_EXPOSURE_COMPENSATION_ENABLED)) {
2191b6c4a314d0a0a185e6d987298ef9b7f4db8a6a2fSenpo Hu            buttonManager.initializePushButton(ButtonManager.BUTTON_EXPOSURE_COMPENSATION,
2192b6c4a314d0a0a185e6d987298ef9b7f4db8a6a2fSenpo Hu                    new View.OnClickListener() {
21930409c8594fd1629ee07df827cf0d7a0f336b9326zafir                        @Override
21940409c8594fd1629ee07df827cf0d7a0f336b9326zafir                        public void onClick(View v) {
21950409c8594fd1629ee07df827cf0d7a0f336b9326zafir                            mModeOptionsOverlay.showExposureOptions();
21960409c8594fd1629ee07df827cf0d7a0f336b9326zafir                        }
21970409c8594fd1629ee07df827cf0d7a0f336b9326zafir                    });
219846acdc5401956ee4951d25d047ae892b78c13d86Spike Sprague            buttonManager.setExposureCompensationParameters(
219957c889d4b88517dd0996547dbae4f314c2a3fcdfzafir                    bottomBarSpec.minExposureCompensation,
220057c889d4b88517dd0996547dbae4f314c2a3fcdfzafir                    bottomBarSpec.maxExposureCompensation,
220157c889d4b88517dd0996547dbae4f314c2a3fcdfzafir                    bottomBarSpec.exposureCompensationStep);
220246acdc5401956ee4951d25d047ae892b78c13d86Spike Sprague
2203abf54e2994961395a0feb0b08353e62718443f23Spike Sprague            buttonManager.setExposureCompensationCallback(
2204abf54e2994961395a0feb0b08353e62718443f23Spike Sprague                    bottomBarSpec.exposureCompensationSetCallback);
2205abf54e2994961395a0feb0b08353e62718443f23Spike Sprague            buttonManager.updateExposureButtons();
22060409c8594fd1629ee07df827cf0d7a0f336b9326zafir        } else if (mController.getSettingsManager().getBoolean(SettingsManager.SCOPE_GLOBAL,
220757c889d4b88517dd0996547dbae4f314c2a3fcdfzafir                Keys.KEY_EXPOSURE_COMPENSATION_ENABLED)
220857c889d4b88517dd0996547dbae4f314c2a3fcdfzafir                && bottomBarSpec.isExposureCompensationSupported) {
22090409c8594fd1629ee07df827cf0d7a0f336b9326zafir            buttonManager.disableButton(ButtonManager.BUTTON_EXPOSURE_COMPENSATION);
2210abf54e2994961395a0feb0b08353e62718443f23Spike Sprague        } else {
2211abf54e2994961395a0feb0b08353e62718443f23Spike Sprague            buttonManager.hideButton(ButtonManager.BUTTON_EXPOSURE_COMPENSATION);
2212abf54e2994961395a0feb0b08353e62718443f23Spike Sprague            buttonManager.setExposureCompensationCallback(null);
2213abf54e2994961395a0feb0b08353e62718443f23Spike Sprague        }
2214abf54e2994961395a0feb0b08353e62718443f23Spike Sprague
2215b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        /** Intent UI */
2216b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        if (bottomBarSpec.showCancel) {
22178ad8ad4841f65ee89e3c5e79f57d95cf8e4438b4Doris Liu            buttonManager.initializePushButton(ButtonManager.BUTTON_CANCEL,
22188ad8ad4841f65ee89e3c5e79f57d95cf8e4438b4Doris Liu                    bottomBarSpec.cancelCallback);
2219b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        }
2220b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        if (bottomBarSpec.showDone) {
22218ad8ad4841f65ee89e3c5e79f57d95cf8e4438b4Doris Liu            buttonManager.initializePushButton(ButtonManager.BUTTON_DONE,
22228ad8ad4841f65ee89e3c5e79f57d95cf8e4438b4Doris Liu                    bottomBarSpec.doneCallback);
2223b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        }
2224b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        if (bottomBarSpec.showRetake) {
22258ad8ad4841f65ee89e3c5e79f57d95cf8e4438b4Doris Liu            buttonManager.initializePushButton(ButtonManager.BUTTON_RETAKE,
2226c989d417a53341b144e9f78304270ac66f8f5813Spike Sprague                    bottomBarSpec.retakeCallback,
2227c989d417a53341b144e9f78304270ac66f8f5813Spike Sprague                    R.drawable.ic_back,
2228c989d417a53341b144e9f78304270ac66f8f5813Spike Sprague                    R.string.retake_button_description);
2229b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren        }
223051c877c56e204ac29a4db72d46168afac3feb239Spike Sprague        if (bottomBarSpec.showReview) {
22318ad8ad4841f65ee89e3c5e79f57d95cf8e4438b4Doris Liu            buttonManager.initializePushButton(ButtonManager.BUTTON_REVIEW,
22328ad8ad4841f65ee89e3c5e79f57d95cf8e4438b4Doris Liu                    bottomBarSpec.reviewCallback,
2233c989d417a53341b144e9f78304270ac66f8f5813Spike Sprague                    R.drawable.ic_play,
2234c989d417a53341b144e9f78304270ac66f8f5813Spike Sprague                    R.string.review_button_description);
223551c877c56e204ac29a4db72d46168afac3feb239Spike Sprague        }
22364efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren    }
2237c813ce181810a444b6fea4a399e6685aef4103e2Sascha Haeberling
2238c813ce181810a444b6fea4a399e6685aef4103e2Sascha Haeberling    /**
22399a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava     * Returns a {@link com.android.camera.ButtonManager.ButtonCallback} that
22409a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava     * will disable the button identified by the parameter.
22419a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava     *
22429a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava     * @param conflictingButton The button id to be disabled.
22439a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava     */
22449a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava    private ButtonManager.ButtonCallback getDisableButtonCallback(final int conflictingButton) {
22459a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava        return new ButtonManager.ButtonCallback() {
22469a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava            @Override
22479a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava            public void onStateChanged(int state) {
22489a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava                mController.getButtonManager().disableButton(conflictingButton);
22499a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava            }
22509a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava        };
22519a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava    }
22529a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava
22534368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava    private String getResourceString(int stringId) {
22544368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava        try {
22554368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava            return mController.getAndroidContext().getResources().getString(stringId);
22564368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava        } catch (Resources.NotFoundException e) {
22574368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava            // String not found, returning empty string.
22584368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava            return "";
22594368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava        }
22604368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava    }
22614368ec0368f69e7604403b4a6db6f1e3123a1814Gabriel Nava
22629a57f184a6f5be46e93dd2f6c66f4b9ba07bdd75Gabriel Nava    /**
2263c813ce181810a444b6fea4a399e6685aef4103e2Sascha Haeberling     * Shows the given tutorial on the screen.
2264c813ce181810a444b6fea4a399e6685aef4103e2Sascha Haeberling     */
2265c813ce181810a444b6fea4a399e6685aef4103e2Sascha Haeberling    public void showTutorial(AbstractTutorialOverlay tutorial, LayoutInflater inflater) {
22661e0810c88e791d0f658eb5a6f95d771ee03a7631Sascha Haeberling        tutorial.show(mTutorialsPlaceHolderWrapper, inflater);
2267c813ce181810a444b6fea4a399e6685aef4103e2Sascha Haeberling    }
2268623dd0c68d64038ed2bcfd264348d9b6f1a13c8aAlan Newberger
226914de25b5c502ffb2ac6396014624206562affef2Gabriel Nava    /**
227014de25b5c502ffb2ac6396014624206562affef2Gabriel Nava     * Whether the capture ratio selector dialog must be shown on this device.
227114de25b5c502ffb2ac6396014624206562affef2Gabriel Nava     * */
227214de25b5c502ffb2ac6396014624206562affef2Gabriel Nava    public boolean shouldShowAspectRatioDialog() {
227314de25b5c502ffb2ac6396014624206562affef2Gabriel Nava        final boolean isAspectRatioPreferenceSet = mController.getSettingsManager().getBoolean(
227414de25b5c502ffb2ac6396014624206562affef2Gabriel Nava                SettingsManager.SCOPE_GLOBAL, Keys.KEY_USER_SELECTED_ASPECT_RATIO);
227514de25b5c502ffb2ac6396014624206562affef2Gabriel Nava        final boolean isAspectRatioDevice =
227614de25b5c502ffb2ac6396014624206562affef2Gabriel Nava                ApiHelper.IS_NEXUS_4 || ApiHelper.IS_NEXUS_5 || ApiHelper.IS_NEXUS_6;
227714de25b5c502ffb2ac6396014624206562affef2Gabriel Nava        return isAspectRatioDevice && !isAspectRatioPreferenceSet;
227814de25b5c502ffb2ac6396014624206562affef2Gabriel Nava    }
227914de25b5c502ffb2ac6396014624206562affef2Gabriel Nava
228014de25b5c502ffb2ac6396014624206562affef2Gabriel Nava
2281623dd0c68d64038ed2bcfd264348d9b6f1a13c8aAlan Newberger    /***************************Filmstrip api *****************************/
2282623dd0c68d64038ed2bcfd264348d9b6f1a13c8aAlan Newberger
2283623dd0c68d64038ed2bcfd264348d9b6f1a13c8aAlan Newberger    public void showFilmstrip() {
2284256427babcb93dd3cdb11b6e23c47ecf82e5af19Sascha Haeberling        mModeListView.onBackPressed();
2285623dd0c68d64038ed2bcfd264348d9b6f1a13c8aAlan Newberger        mFilmstripLayout.showFilmstrip();
2286623dd0c68d64038ed2bcfd264348d9b6f1a13c8aAlan Newberger    }
22878099a371048e45b9161ac63e4d6bd9644fcad5b5Alan Newberger
22888099a371048e45b9161ac63e4d6bd9644fcad5b5Alan Newberger    public void hideFilmstrip() {
22898099a371048e45b9161ac63e4d6bd9644fcad5b5Alan Newberger        mFilmstripLayout.hideFilmstrip();
22908099a371048e45b9161ac63e4d6bd9644fcad5b5Alan Newberger    }
229186f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger
229286f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger    public int getFilmstripVisibility() {
229386f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger        return mFilmstripLayout.getVisibility();
229486f1d1f3664c909d1d949951056c7bb1e9627324Alan Newberger    }
2295f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu}
2296