1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.camera.captureintent;
18 
19 import com.android.camera.app.CameraAppUI;
20 import com.android.camera.async.MainThread;
21 import com.android.camera.hardware.HardwareSpec;
22 import com.android.camera.ui.CountDownView;
23 import com.android.camera.ui.PreviewOverlay;
24 import com.android.camera.ui.PreviewStatusListener;
25 import com.android.camera.ui.ProgressOverlay;
26 import com.android.camera.ui.focus.FocusRing;
27 import com.android.camera.util.AndroidServices;
28 import com.android.camera.util.Size;
29 import com.android.camera2.R;
30 
31 import android.graphics.Bitmap;
32 import android.graphics.Matrix;
33 import android.graphics.RectF;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.ViewGroup;
37 import android.widget.FrameLayout;
38 import android.widget.ImageView;
39 
40 /**
41  * Contains the UI for the ImageCaptureIntentModule.
42  */
43 public class CaptureIntentModuleUI {
44     public interface Listener {
onZoomRatioChanged(float zoomRatio)45         public void onZoomRatioChanged(float zoomRatio);
46     }
47     private final Listener mListener;
48 
49     private final CameraAppUI mAppUI;
50     private final View mRootView;
51     private final PreviewOverlay mPreviewOverlay;
52     private final ProgressOverlay mProgressOverlay;
53     private final FocusRing mFocusRing;
54     private final CountDownView mCountdownView;
55 
56     /** The image view to display the captured picture. */
57     private final ImageView mIntentReviewImageView;
58 
59     /** The layout rect of the preview. */
60     private RectF mPreviewRect;
61 
62     private final PreviewStatusListener.PreviewAreaChangedListener mPreviewAreaChangedListener =
63             new PreviewStatusListener.PreviewAreaChangedListener() {
64                 @Override
65                 public void onPreviewAreaChanged(RectF previewArea) {
66                     mPreviewRect = previewArea;
67                     mCountdownView.onPreviewAreaChanged(previewArea);
68                     mProgressOverlay.setBounds(previewArea);
69                     FrameLayout.LayoutParams params =
70                             (FrameLayout.LayoutParams) mIntentReviewImageView.getLayoutParams();
71 
72                     /**
73                      * WAR for b/19676505: On Nexus 6 / 16:9 / portrait, for
74                      * some reasons the previewArea width is 1345.499999999....
75                      * Use Math.ceil here to make the width 1346.
76                      */
77                     params.width = (int) Math.ceil((double) previewArea.width());
78 
79                     params.height = Math.round(previewArea.height());
80                     params.setMargins(
81                             Math.round(previewArea.left), Math.round(previewArea.top), 0, 0);
82                     mIntentReviewImageView.setLayoutParams(params);
83                 }
84             };
85 
CaptureIntentModuleUI( CameraAppUI appUI, View parent, Listener listener)86     public CaptureIntentModuleUI(
87             CameraAppUI appUI, View parent, Listener listener) {
88 
89         mAppUI = appUI;
90         mListener = listener;
91         mRootView = parent;
92 
93         mIntentReviewImageView = (ImageView) mRootView.findViewById(R.id.intent_review_imageview);
94 
95         final LayoutInflater layoutInflater = AndroidServices.instance().provideLayoutInflater();
96 
97         ViewGroup moduleRoot = (ViewGroup) mRootView.findViewById(R.id.module_layout);
98         layoutInflater.inflate(R.layout.capture_module, moduleRoot, true);
99 
100         mPreviewOverlay = (PreviewOverlay) mRootView.findViewById(R.id.preview_overlay);
101         mProgressOverlay = (ProgressOverlay) mRootView.findViewById(R.id.progress_overlay);
102         mFocusRing = (FocusRing) mRootView.findViewById(R.id.focus_ring);
103         mCountdownView = (CountDownView) mRootView.findViewById(R.id.count_down_view);
104 
105         mPreviewRect = new RectF(0, 0, 0, 0);
106     }
107 
108     /**
109      * Obtains the current preview layout rect.
110      */
getPreviewRect()111     public RectF getPreviewRect() {
112         return mPreviewRect;
113     }
114 
115     /**
116      * Obtains the current preview layout size.
117      */
getPreviewSurfaceSize()118     public Size getPreviewSurfaceSize() {
119         return new Size(mAppUI.getSurfaceWidth(), mAppUI.getSurfaceHeight());
120     }
121 
122     /**
123      * Configures the bottom bar UI.
124      *
125      * @param hardwareSpec The hardware spec.
126      * @param bottomBarSpec The bottom bar spec.
127      */
applyModuleSpecs( HardwareSpec hardwareSpec, CameraAppUI.BottomBarUISpec bottomBarSpec)128     public void applyModuleSpecs(
129             HardwareSpec hardwareSpec,
130             CameraAppUI.BottomBarUISpec bottomBarSpec) {
131         MainThread.checkMainThread();
132         mAppUI.applyModuleSpecs(hardwareSpec, bottomBarSpec);
133     }
134 
135     /**
136      * Called when the module got resumed.
137      */
onModuleResumed()138     public void onModuleResumed() {
139         MainThread.checkMainThread();
140         // Listen to preview layout change event. Adjust review image view
141         // layout to match preview layout.
142         //
143         // Doing this here rather than in ctor is because TextureViewHelper
144         // doesn't exist until the module got initialized.
145         mAppUI.addPreviewAreaChangedListener(mPreviewAreaChangedListener);
146     }
147 
148     /**
149      * Called when the module got paused.
150      */
onModulePaused()151     public void onModulePaused() {
152         MainThread.checkMainThread();
153         mAppUI.removePreviewAreaChangedListener(mPreviewAreaChangedListener);
154     }
155 
156     /**
157      * Update preview transform matrix.
158      *
159      * @param matrix The preview transform matrix.
160      */
updatePreviewTransform(Matrix matrix)161     public void updatePreviewTransform(Matrix matrix) {
162         MainThread.checkMainThread();
163         mAppUI.updatePreviewTransform(matrix);
164     }
165 
166     /**
167      * Update preview aspect ratio.
168      *
169      * This is useful only when TextureViewHelper auto transform is enabled.
170      *
171      * @param aspectRatio The preview aspect ratio.
172      */
updatePreviewAspectRatio(float aspectRatio)173     public void updatePreviewAspectRatio(float aspectRatio) {
174         MainThread.checkMainThread();
175         mAppUI.updatePreviewAspectRatio(aspectRatio);
176     }
177 
178     /**
179      * Called when the preview is started.
180      */
onPreviewStarted()181     public void onPreviewStarted() {
182         MainThread.checkMainThread();
183         mAppUI.onPreviewStarted();
184     }
185 
186     /**
187      * Enables zoom UI, setting maximum zoom.
188      * Called from Module when camera is available.
189      *
190      * @param maxZoom maximum zoom value.
191      */
initializeZoom(float maxZoom)192     public void initializeZoom(float maxZoom) {
193         MainThread.checkMainThread();
194         mPreviewOverlay.setupZoom(maxZoom, 0, mZoomChancedListener);
195     }
196 
getFocusRing()197     public FocusRing getFocusRing() {
198         return mFocusRing;
199     }
200 
setShutterButtonEnabled(boolean enabled)201     public void setShutterButtonEnabled(boolean enabled) {
202         MainThread.checkMainThread();
203         mAppUI.setShutterButtonEnabled(enabled);
204     }
205 
startFlashAnimation(boolean shortFlash)206     public void startFlashAnimation(boolean shortFlash) {
207         MainThread.checkMainThread();
208         mAppUI.startFlashAnimation(shortFlash);
209     }
210 
211     /**
212      * Starts the countdown timer.
213      *
214      * @param sec seconds to countdown
215      */
startCountdown(int sec)216     public void startCountdown(int sec) {
217         MainThread.checkMainThread();
218         mAppUI.transitionToCancel();
219         mCountdownView.startCountDown(sec);
220     }
221 
222     /**
223      * Cancels the on-going countdown, if any.
224      */
cancelCountDown()225     public void cancelCountDown() {
226         mCountdownView.cancelCountDown();
227     }
228 
229     /**
230      * Sets a listener that gets notified when the countdown is finished.
231      */
setCountdownFinishedListener(CountDownView.OnCountDownStatusListener listener)232     public void setCountdownFinishedListener(CountDownView.OnCountDownStatusListener listener) {
233         mCountdownView.setCountDownStatusListener(listener);
234     }
235 
236     /**
237      * Transition to the UI where users can review the taken photo.
238      *
239      * @param reviewPictureBitmap The picture bitmap to be shown.
240      */
showPictureReviewUI(Bitmap reviewPictureBitmap)241     public void showPictureReviewUI(Bitmap reviewPictureBitmap) {
242         MainThread.checkMainThread();
243 
244         mIntentReviewImageView.setImageBitmap(reviewPictureBitmap);
245         mIntentReviewImageView.setVisibility(View.VISIBLE);
246 
247         mAppUI.transitionToIntentReviewLayout();
248         mAppUI.hideModeOptions();
249         mAppUI.disableModeOptions();
250         mAppUI.setShutterButtonEnabled(false);
251     }
252 
253     /**
254      * Transition to the UI where users can take a photo.
255      */
showPictureCaptureUI()256     public void showPictureCaptureUI() {
257         MainThread.checkMainThread();
258 
259         mIntentReviewImageView.setVisibility(View.INVISIBLE);
260         mIntentReviewImageView.setImageBitmap(null);
261 
262         mAppUI.transitionToIntentCaptureLayout();
263         mAppUI.syncModeOptionIndicators();
264         mAppUI.enableModeOptions();
265         mAppUI.showModeOptions();
266         mAppUI.setShutterButtonEnabled(true);
267         mAppUI.setShouldSuppressCaptureIndicator(true);
268     }
269 
freezeScreenUntilPreviewReady()270     public void freezeScreenUntilPreviewReady() {
271         MainThread.checkMainThread();
272         mAppUI.freezeScreenUntilPreviewReady();
273     }
274 
275     /** Set up listener to receive zoom changes from View and send to module. */
276     private final PreviewOverlay.OnZoomChangedListener mZoomChancedListener =
277             new PreviewOverlay.OnZoomChangedListener() {
278         @Override
279         public void onZoomValueChanged(float ratio) {
280             mListener.onZoomRatioChanged(ratio);
281         }
282 
283         @Override
284         public void onZoomStart() {
285         }
286 
287         @Override
288         public void onZoomEnd() {
289         }
290     };
291 }
292