blob: 6e59bf9d99839775c1e0ccbdea9f99c635edb71b [file] [log] [blame]
Michael Kolbd6954f32013-03-08 20:43:01 -08001/*
Doris Liu6432cd62013-06-13 17:20:31 -07002 * Copyright (C) 2012 The Android Open Source Project
Michael Kolbd6954f32013-03-08 20:43:01 -08003 *
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
Michael Kolbd6954f32013-03-08 20:43:01 -080017package com.android.camera;
18
Doris Liudb8f9752014-05-12 15:25:13 -070019import android.app.Dialog;
20import android.content.DialogInterface;
Sascha Haeberling37f36112013-08-06 14:31:52 -070021import android.graphics.Bitmap;
Doris Liu6432cd62013-06-13 17:20:31 -070022import android.graphics.Matrix;
Doris Liu6c751642014-05-05 18:43:26 -070023import android.graphics.RectF;
Doris Liu6432cd62013-06-13 17:20:31 -070024import android.graphics.SurfaceTexture;
Michael Kolbd6954f32013-03-08 20:43:01 -080025import android.hardware.Camera.Face;
Sascha Haeberling37f36112013-08-06 14:31:52 -070026import android.os.AsyncTask;
Doris Liuf9e4f8f2013-12-04 18:04:22 -080027import android.view.GestureDetector;
28import android.view.MotionEvent;
Michael Kolbd6954f32013-03-08 20:43:01 -080029import android.view.View;
Michael Kolbd6954f32013-03-08 20:43:01 -080030import android.view.ViewGroup;
Spike Spragueb4a22222014-05-22 14:40:53 -070031import android.widget.FrameLayout;
32import android.widget.ImageView;
Michael Kolbd6954f32013-03-08 20:43:01 -080033
Andy Huibers62b4c3c2014-08-25 15:01:25 -070034import com.android.camera.debug.DebugPropertyHelper;
Angus Kong5596b4c2014-03-11 16:27:30 -070035import com.android.camera.debug.Log;
Doris Liu6c751642014-05-05 18:43:26 -070036import com.android.camera.ui.CountDownView;
Michael Kolbd6954f32013-03-08 20:43:01 -080037import com.android.camera.ui.FaceView;
Doris Liuf9e4f8f2013-12-04 18:04:22 -080038import com.android.camera.ui.PreviewOverlay;
Doris Liu06db7422013-12-09 19:36:25 -080039import com.android.camera.ui.PreviewStatusListener;
Paul Rohde987ee642014-12-05 12:17:15 -080040import com.android.camera.ui.focus.FocusRing;
Alan Newberger2631a152014-09-24 14:23:30 -070041import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -070042import com.android.camera.util.CameraUtil;
Alan Newberger2631a152014-09-24 14:23:30 -070043import com.android.camera.util.GservicesHelper;
Doris Liudb8f9752014-05-12 15:25:13 -070044import com.android.camera.widget.AspectRatioDialogLayout;
45import com.android.camera.widget.AspectRatioSelector;
46import com.android.camera.widget.LocationDialogLayout;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070047import com.android.camera2.R;
Sol Boucher5a344962014-06-17 14:05:08 -070048import com.android.ex.camera2.portability.CameraAgent;
Sascha Haeberling4c1bffe2014-08-21 10:01:00 -070049import com.android.ex.camera2.portability.CameraCapabilities;
Sol Boucher5a344962014-06-17 14:05:08 -070050import com.android.ex.camera2.portability.CameraSettings;
Angus Kongb50b5cb2013-08-09 14:55:20 -070051
Doris Liu482de022013-12-18 19:18:16 -080052public class PhotoUI implements PreviewStatusListener,
Sol Boucher5a344962014-06-17 14:05:08 -070053 CameraAgent.CameraFaceDetectionCallback, PreviewStatusListener.PreviewAreaChangedListener {
Michael Kolbd6954f32013-03-08 20:43:01 -080054
Angus Kong5596b4c2014-03-11 16:27:30 -070055 private static final Log.Tag TAG = new Log.Tag("PhotoUI");
Sascha Haeberling37f36112013-08-06 14:31:52 -070056 private static final int DOWN_SAMPLE_FACTOR = 4;
Doris Liu70da9182013-12-17 18:41:15 -080057 private static final float UNSET = 0f;
Spike Sprague0f3c4b42013-12-10 19:50:17 -080058
Doris Liuf9e4f8f2013-12-04 18:04:22 -080059 private final PreviewOverlay mPreviewOverlay;
Paul Rohde987ee642014-12-05 12:17:15 -080060 private final FocusRing mFocusRing;
Sascha Haeberlinge2914fd2014-01-17 19:03:52 -080061 private final CameraActivity mActivity;
62 private final PhotoController mController;
Michael Kolbd6954f32013-03-08 20:43:01 -080063
Sascha Haeberlinge2914fd2014-01-17 19:03:52 -080064 private final View mRootView;
Doris Liudb8f9752014-05-12 15:25:13 -070065 private Dialog mDialog = null;
Michael Kolbd6954f32013-03-08 20:43:01 -080066
Doris Liud27ea7b2014-02-25 11:46:11 -080067 // TODO: Remove face view logic if UX does not bring it back within a month.
Andy Huibers62b4c3c2014-08-25 15:01:25 -070068 private final FaceView mFaceView;
Doris Liu36e56fb2013-09-11 17:38:08 -070069 private DecodeImageForReview mDecodeTaskForReview = null;
Michael Kolbd6954f32013-03-08 20:43:01 -080070
Sol Boucher2192fba2014-08-19 17:24:07 -070071 private float mZoomMax;
Michael Kolbd6954f32013-03-08 20:43:01 -080072
73 private int mPreviewWidth = 0;
74 private int mPreviewHeight = 0;
Doris Liu70da9182013-12-17 18:41:15 -080075 private float mAspectRatio = UNSET;
Marco Nelissen0744e4a2013-11-22 01:47:37 +000076
Spike Spragueb4a22222014-05-22 14:40:53 -070077 private ImageView mIntentReviewImageView;
78
Doris Liu06db7422013-12-09 19:36:25 -080079 private final GestureDetector.OnGestureListener mPreviewGestureListener
80 = new GestureDetector.SimpleOnGestureListener() {
81 @Override
82 public boolean onSingleTapUp(MotionEvent ev) {
83 mController.onSingleTapUp(null, (int) ev.getX(), (int) ev.getY());
84 return true;
85 }
86 };
Doris Liudb8f9752014-05-12 15:25:13 -070087 private final DialogInterface.OnDismissListener mOnDismissListener
88 = new DialogInterface.OnDismissListener() {
89 @Override
90 public void onDismiss(DialogInterface dialog) {
91 mDialog = null;
92 }
93 };
Doris Liu08b0cdd2014-05-13 19:19:55 -070094 private Runnable mRunnableForNextFrame = null;
Sascha Haeberling4c1bffe2014-08-21 10:01:00 -070095 private final CountDownView mCountdownView;
Marco Nelissen0744e4a2013-11-22 01:47:37 +000096
Doris Liu06db7422013-12-09 19:36:25 -080097 @Override
98 public GestureDetector.OnGestureListener getGestureListener() {
99 return mPreviewGestureListener;
100 }
101
Doris Liu4a010db2013-12-16 18:44:49 -0800102 @Override
Erin Dahlgrend8de0772014-02-03 10:12:27 -0800103 public View.OnTouchListener getTouchListener() {
104 return null;
105 }
106
107 @Override
Doris Liu4a010db2013-12-16 18:44:49 -0800108 public void onPreviewLayoutChanged(View v, int left, int top, int right,
109 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
110 int width = right - left;
111 int height = bottom - top;
112 if (mPreviewWidth != width || mPreviewHeight != height) {
113 mPreviewWidth = width;
114 mPreviewHeight = height;
Michael Kolbd6954f32013-03-08 20:43:01 -0800115 }
Doris Liu4a010db2013-12-16 18:44:49 -0800116 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800117
Doris Liu70da9182013-12-17 18:41:15 -0800118 @Override
119 public boolean shouldAutoAdjustTransformMatrixOnLayout() {
120 return true;
121 }
122
123 @Override
124 public boolean shouldAutoAdjustBottomBar() {
125 return true;
126 }
127
Doris Liu11ddd732014-01-07 10:52:11 -0800128 @Override
129 public void onPreviewFlipped() {
130 mController.updateCameraOrientation();
131 }
132
Doris Liu08b0cdd2014-05-13 19:19:55 -0700133 /**
134 * Sets the runnable to run when the next frame comes in.
135 */
136 public void setRunnableForNextFrame(Runnable runnable) {
137 mRunnableForNextFrame = runnable;
138 }
139
Doris Liu6c751642014-05-05 18:43:26 -0700140 /**
141 * Starts the countdown timer.
142 *
143 * @param sec seconds to countdown
144 */
145 public void startCountdown(int sec) {
146 mCountdownView.startCountDown(sec);
147 }
148
149 /**
150 * Sets a listener that gets notified when the countdown is finished.
151 */
152 public void setCountdownFinishedListener(CountDownView.OnCountDownStatusListener listener) {
153 mCountdownView.setCountDownStatusListener(listener);
154 }
155
156 /**
157 * Returns whether the countdown is on-going.
158 */
159 public boolean isCountingDown() {
160 return mCountdownView.isCountingDown();
161 }
162
163 /**
164 * Cancels the on-going countdown, if any.
165 */
166 public void cancelCountDown() {
167 mCountdownView.cancelCountDown();
168 }
169
170 @Override
171 public void onPreviewAreaChanged(RectF previewArea) {
172 if (mFaceView != null) {
173 mFaceView.onPreviewAreaChanged(previewArea);
174 }
175 mCountdownView.onPreviewAreaChanged(previewArea);
176 }
177
Doris Liu36e56fb2013-09-11 17:38:08 -0700178 private class DecodeTask extends AsyncTask<Void, Void, Bitmap> {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700179 private final byte [] mData;
Sascha Haeberlinge2914fd2014-01-17 19:03:52 -0800180 private final int mOrientation;
181 private final boolean mMirror;
Doris Liuc2e9abd2013-06-19 14:20:51 -0700182
Doris Liu29da2db2013-08-28 14:28:45 -0700183 public DecodeTask(byte[] data, int orientation, boolean mirror) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700184 mData = data;
Doris Liuce2acbc2013-08-21 18:45:29 -0700185 mOrientation = orientation;
Doris Liu29da2db2013-08-28 14:28:45 -0700186 mMirror = mirror;
Doris Liuc2e9abd2013-06-19 14:20:51 -0700187 }
188
189 @Override
Doris Liu36e56fb2013-09-11 17:38:08 -0700190 protected Bitmap doInBackground(Void... params) {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700191 // Decode image in background.
Doris Liuce2acbc2013-08-21 18:45:29 -0700192 Bitmap bitmap = CameraUtil.downSample(mData, DOWN_SAMPLE_FACTOR);
Doris Liu29da2db2013-08-28 14:28:45 -0700193 if (mOrientation != 0 || mMirror) {
Doris Liuce2acbc2013-08-21 18:45:29 -0700194 Matrix m = new Matrix();
Doris Liu29da2db2013-08-28 14:28:45 -0700195 if (mMirror) {
196 // Flip horizontally
197 m.setScale(-1f, 1f);
198 }
Andy Huiberscec75e42013-10-29 16:03:58 -0700199 m.preRotate(mOrientation);
Doris Liuce2acbc2013-08-21 18:45:29 -0700200 return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m,
201 false);
202 }
203 return bitmap;
Sascha Haeberling37f36112013-08-06 14:31:52 -0700204 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700205 }
Doris Liuc2e9abd2013-06-19 14:20:51 -0700206
Doris Liu36e56fb2013-09-11 17:38:08 -0700207 private class DecodeImageForReview extends DecodeTask {
208 public DecodeImageForReview(byte[] data, int orientation, boolean mirror) {
209 super(data, orientation, mirror);
210 }
211
212 @Override
213 protected void onPostExecute(Bitmap bitmap) {
214 if (isCancelled()) {
215 return;
216 }
Spike Spragueb4a22222014-05-22 14:40:53 -0700217
218 mIntentReviewImageView.setImageBitmap(bitmap);
219 showIntentReviewImageView();
220
Doris Liu36e56fb2013-09-11 17:38:08 -0700221 mDecodeTaskForReview = null;
222 }
223 }
224
Michael Kolbd6954f32013-03-08 20:43:01 -0800225 public PhotoUI(CameraActivity activity, PhotoController controller, View parent) {
226 mActivity = activity;
227 mController = controller;
228 mRootView = parent;
229
Doris Liuf55f3c42013-11-20 00:24:46 -0800230 ViewGroup moduleRoot = (ViewGroup) mRootView.findViewById(R.id.module_layout);
Michael Kolbd6954f32013-03-08 20:43:01 -0800231 mActivity.getLayoutInflater().inflate(R.layout.photo_module,
Sascha Haeberlinge2914fd2014-01-17 19:03:52 -0800232 moduleRoot, true);
Michael Kolbd6954f32013-03-08 20:43:01 -0800233 initIndicators();
Paul Rohde987ee642014-12-05 12:17:15 -0800234 mFocusRing = (FocusRing) mRootView.findViewById(R.id.focus_ring);
Doris Liuf9e4f8f2013-12-04 18:04:22 -0800235 mPreviewOverlay = (PreviewOverlay) mRootView.findViewById(R.id.preview_overlay);
Doris Liu6c751642014-05-05 18:43:26 -0700236 mCountdownView = (CountDownView) mRootView.findViewById(R.id.count_down_view);
Andy Huibers62b4c3c2014-08-25 15:01:25 -0700237 // Show faces if we are in debug mode.
238 if (DebugPropertyHelper.showCaptureDebugUI()) {
239 mFaceView = (FaceView) mRootView.findViewById(R.id.face_view);
240 } else {
241 mFaceView = null;
242 }
Spike Spragueb4a22222014-05-22 14:40:53 -0700243
244 if (mController.isImageCaptureIntent()) {
Spike Sprague02b9b9a2014-07-02 11:26:28 -0700245 initIntentReviewImageView();
Spike Spragueb4a22222014-05-22 14:40:53 -0700246 }
Doris Liu6432cd62013-06-13 17:20:31 -0700247 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800248
Spike Sprague02b9b9a2014-07-02 11:26:28 -0700249 private void initIntentReviewImageView() {
250 mIntentReviewImageView = (ImageView) mRootView.findViewById(R.id.intent_review_imageview);
Spike Spragueb4a22222014-05-22 14:40:53 -0700251 mActivity.getCameraAppUI().addPreviewAreaChangedListener(
252 new PreviewStatusListener.PreviewAreaChangedListener() {
253 @Override
254 public void onPreviewAreaChanged(RectF previewArea) {
255 FrameLayout.LayoutParams params =
256 (FrameLayout.LayoutParams) mIntentReviewImageView.getLayoutParams();
257 params.width = (int) previewArea.width();
258 params.height = (int) previewArea.height();
259 params.setMargins((int) previewArea.left, (int) previewArea.top, 0, 0);
260 mIntentReviewImageView.setLayoutParams(params);
261 }
262 });
263 }
264
265 /**
266 * Show the image review over the live preview for intent captures.
267 */
268 public void showIntentReviewImageView() {
269 if (mIntentReviewImageView != null) {
270 mIntentReviewImageView.setVisibility(View.VISIBLE);
271 }
272 }
273
274 /**
275 * Hide the image review over the live preview for intent captures.
276 */
277 public void hideIntentReviewImageView() {
278 if (mIntentReviewImageView != null) {
279 mIntentReviewImageView.setVisibility(View.INVISIBLE);
280 }
281 }
282
283
Paul Rohde987ee642014-12-05 12:17:15 -0800284 public FocusRing getFocusRing() {
285 return mFocusRing;
Doris Liu482de022013-12-18 19:18:16 -0800286 }
287
Doris Liud053a5b2013-10-25 20:20:43 -0700288 public void updatePreviewAspectRatio(float aspectRatio) {
289 if (aspectRatio <= 0) {
290 Log.e(TAG, "Invalid aspect ratio: " + aspectRatio);
291 return;
292 }
293 if (aspectRatio < 1f) {
294 aspectRatio = 1f / aspectRatio;
295 }
296
297 if (mAspectRatio != aspectRatio) {
298 mAspectRatio = aspectRatio;
299 // Update transform matrix with the new aspect ratio.
Doris Liu70da9182013-12-17 18:41:15 -0800300 mController.updatePreviewAspectRatio(mAspectRatio);
Doris Liud053a5b2013-10-25 20:20:43 -0700301 }
302 }
303
Angus Kongdcccc512013-08-08 17:06:03 -0700304 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700305 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Erin Dahlgrend8de0772014-02-03 10:12:27 -0800306 mController.onPreviewUIReady();
Doris Liu6432cd62013-06-13 17:20:31 -0700307 }
308
Angus Kongdcccc512013-08-08 17:06:03 -0700309 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700310 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
311 // Ignored, Camera does all the work for us
312 }
313
Angus Kongdcccc512013-08-08 17:06:03 -0700314 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700315 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
Erin Dahlgrend8de0772014-02-03 10:12:27 -0800316 mController.onPreviewUIDestroyed();
317 return true;
Doris Liu6432cd62013-06-13 17:20:31 -0700318 }
319
ztenghui7b265a62013-09-09 14:58:44 -0700320 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700321 public void onSurfaceTextureUpdated(SurfaceTexture surface) {
Doris Liu08b0cdd2014-05-13 19:19:55 -0700322 if (mRunnableForNextFrame != null) {
323 mRootView.post(mRunnableForNextFrame);
324 mRunnableForNextFrame = null;
325 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800326 }
327
328 public View getRootView() {
329 return mRootView;
330 }
331
332 private void initIndicators() {
Marco Nelissen0744e4a2013-11-22 01:47:37 +0000333 // TODO init toggle buttons on bottom bar here
Michael Kolbd6954f32013-03-08 20:43:01 -0800334 }
335
Angus Kong6607dae2014-06-10 16:07:45 -0700336 public void onCameraOpened(CameraCapabilities capabilities, CameraSettings settings) {
337 initializeZoom(capabilities, settings);
Michael Kolbd6954f32013-03-08 20:43:01 -0800338 }
339
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800340 public void animateCapture(final byte[] jpegData, int orientation, boolean mirror) {
341 // Decode jpeg byte array and then animate the jpeg
342 DecodeTask task = new DecodeTask(jpegData, orientation, mirror);
343 task.execute();
Spike Spragueeb3134f2013-12-12 11:14:27 -0800344 }
345
Michael Kolbd6954f32013-03-08 20:43:01 -0800346 // called from onResume but only the first time
Kevin Gabayanffbc43c2013-12-09 11:41:50 -0800347 public void initializeFirstTime() {
Marco Nelissen0744e4a2013-11-22 01:47:37 +0000348
Michael Kolbd6954f32013-03-08 20:43:01 -0800349 }
350
351 // called from onResume every other time
Angus Kong6607dae2014-06-10 16:07:45 -0700352 public void initializeSecondTime(CameraCapabilities capabilities, CameraSettings settings) {
353 initializeZoom(capabilities, settings);
Michael Kolbd6954f32013-03-08 20:43:01 -0800354 if (mController.isImageCaptureIntent()) {
355 hidePostCaptureAlert();
356 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800357 }
358
Doris Liudb8f9752014-05-12 15:25:13 -0700359 public void showLocationAndAspectRatioDialog(
360 final PhotoModule.LocationDialogCallback locationCallback,
361 final PhotoModule.AspectRatioDialogCallback aspectRatioDialogCallback) {
362 setDialog(new Dialog(mActivity,
363 android.R.style.Theme_Black_NoTitleBar_Fullscreen));
364 final LocationDialogLayout locationDialogLayout = (LocationDialogLayout) mActivity
365 .getLayoutInflater().inflate(R.layout.location_dialog_layout, null);
366 locationDialogLayout.setLocationTaggingSelectionListener(
367 new LocationDialogLayout.LocationTaggingSelectionListener() {
368 @Override
369 public void onLocationTaggingSelected(boolean selected) {
370 // Update setting.
371 locationCallback.onLocationTaggingSelected(selected);
Sascha Haeberling1d943642014-05-19 11:56:53 -0700372
373 if (showAspectRatioDialogOnThisDevice()) {
374 // Go to next page.
375 showAspectRatioDialog(aspectRatioDialogCallback, mDialog);
376 } else {
377 // If we don't want to show the aspect ratio dialog,
378 // dismiss the dialog right after the user chose the
379 // location setting.
380 if (mDialog != null) {
381 mDialog.dismiss();
382 }
383 }
Doris Liudb8f9752014-05-12 15:25:13 -0700384 }
385 });
386 mDialog.setContentView(locationDialogLayout, new ViewGroup.LayoutParams(
387 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
388 mDialog.show();
389 }
390
391 /**
392 * Dismisses previous dialog if any, sets current dialog to the given dialog,
393 * and set the on dismiss listener for the given dialog.
394 * @param dialog dialog to show
395 */
396 private void setDialog(Dialog dialog) {
397 if (mDialog != null) {
398 mDialog.setOnDismissListener(null);
399 mDialog.dismiss();
400 }
401 mDialog = dialog;
402 if (mDialog != null) {
403 mDialog.setOnDismissListener(mOnDismissListener);
404 }
405 }
406
Sascha Haeberling4c1bffe2014-08-21 10:01:00 -0700407 /**
408 * @return Whether the dialog was shown.
409 */
410 public boolean showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback) {
Sascha Haeberling1d943642014-05-19 11:56:53 -0700411 if (showAspectRatioDialogOnThisDevice()) {
412 setDialog(new Dialog(mActivity, android.R.style.Theme_Black_NoTitleBar_Fullscreen));
413 showAspectRatioDialog(callback, mDialog);
Sascha Haeberling4c1bffe2014-08-21 10:01:00 -0700414 return true;
415 } else {
416 return false;
Sascha Haeberling1d943642014-05-19 11:56:53 -0700417 }
Doris Liudb8f9752014-05-12 15:25:13 -0700418 }
419
Sascha Haeberling4c1bffe2014-08-21 10:01:00 -0700420 private boolean showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback,
Doris Liudb8f9752014-05-12 15:25:13 -0700421 final Dialog aspectRatioDialog) {
422 if (aspectRatioDialog == null) {
423 Log.e(TAG, "Dialog for aspect ratio is null.");
Sascha Haeberling4c1bffe2014-08-21 10:01:00 -0700424 return false;
Doris Liudb8f9752014-05-12 15:25:13 -0700425 }
426 final AspectRatioDialogLayout aspectRatioDialogLayout =
427 (AspectRatioDialogLayout) mActivity
428 .getLayoutInflater().inflate(R.layout.aspect_ratio_dialog_layout, null);
429 aspectRatioDialogLayout.initialize(
430 new AspectRatioDialogLayout.AspectRatioChangedListener() {
431 @Override
432 public void onAspectRatioChanged(AspectRatioSelector.AspectRatio aspectRatio) {
Doris Liudb8f9752014-05-12 15:25:13 -0700433 // callback to set picture size.
Doris Liu08b0cdd2014-05-13 19:19:55 -0700434 callback.onAspectRatioSelected(aspectRatio, new Runnable() {
435 @Override
436 public void run() {
437 if (mDialog != null) {
438 mDialog.dismiss();
439 }
440 }
441 });
Doris Liudb8f9752014-05-12 15:25:13 -0700442 }
Sascha Haeberlinge811b292014-05-19 14:47:09 -0700443 }, callback.getCurrentAspectRatio());
Doris Liudb8f9752014-05-12 15:25:13 -0700444 aspectRatioDialog.setContentView(aspectRatioDialogLayout, new ViewGroup.LayoutParams(
445 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
446 aspectRatioDialog.show();
Sascha Haeberling4c1bffe2014-08-21 10:01:00 -0700447 return true;
Doris Liu6a83d522013-07-02 12:03:32 -0700448 }
449
Sascha Haeberling1d943642014-05-19 11:56:53 -0700450 /**
451 * @return Whether this is a device that we should show the aspect ratio
452 * intro dialog on.
453 */
454 private boolean showAspectRatioDialogOnThisDevice() {
Alan Newberger2631a152014-09-24 14:23:30 -0700455 // We only want to show that dialog on N4/N5/N6
456 // Don't show if using API2 portability, b/17462976
457 return !GservicesHelper.useCamera2ApiThroughPortabilityLayer(mActivity) &&
458 (ApiHelper.IS_NEXUS_4 || ApiHelper.IS_NEXUS_5 || ApiHelper.IS_NEXUS_6);
Sascha Haeberling1d943642014-05-19 11:56:53 -0700459 }
460
Angus Kong6607dae2014-06-10 16:07:45 -0700461 public void initializeZoom(CameraCapabilities capabilities, CameraSettings settings) {
462 if ((capabilities == null) || settings == null ||
463 !capabilities.supports(CameraCapabilities.Feature.ZOOM)) {
Sascha Haeberling1d943642014-05-19 11:56:53 -0700464 return;
465 }
Sol Boucher2192fba2014-08-19 17:24:07 -0700466 mZoomMax = capabilities.getMaxZoomRatio();
Michael Kolbd6954f32013-03-08 20:43:01 -0800467 // Currently we use immediate zoom for fast zooming to get better UX and
468 // there is no plan to take advantage of the smooth zoom.
Doris Liuf9e4f8f2013-12-04 18:04:22 -0800469 // TODO: Need to setup a path to AppUI to do this
Sol Boucher2192fba2014-08-19 17:24:07 -0700470 mPreviewOverlay.setupZoom(mZoomMax, settings.getCurrentZoomRatio(),
Angus Kong6607dae2014-06-10 16:07:45 -0700471 new ZoomChangeListener());
Michael Kolbd6954f32013-03-08 20:43:01 -0800472 }
473
Doris Liuc2e9abd2013-06-19 14:20:51 -0700474 public void animateFlash() {
Doris Liu1dfe7822013-12-12 00:02:08 -0800475 mController.startPreCaptureAnimation();
Doris Liuc2e9abd2013-06-19 14:20:51 -0700476 }
477
Michael Kolbd6954f32013-03-08 20:43:01 -0800478 public boolean onBackPressed() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800479 // In image capture mode, back button should:
480 // 1) if there is any popup, dismiss them, 2) otherwise, get out of
481 // image capture
482 if (mController.isImageCaptureIntent()) {
Doris Liuc3679c02013-08-08 18:08:43 -0700483 mController.onCaptureCancelled();
Michael Kolbd6954f32013-03-08 20:43:01 -0800484 return true;
485 } else if (!mController.isCameraIdle()) {
486 // ignore backs while we're taking a picture
487 return true;
488 } else {
Doris Liuc3679c02013-08-08 18:08:43 -0700489 return false;
Michael Kolbd6954f32013-03-08 20:43:01 -0800490 }
491 }
492
Doris Liu36e56fb2013-09-11 17:38:08 -0700493 protected void showCapturedImageForReview(byte[] jpegData, int orientation, boolean mirror) {
494 mDecodeTaskForReview = new DecodeImageForReview(jpegData, orientation, mirror);
495 mDecodeTaskForReview.execute();
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800496
Erin Dahlgren4efa8b52013-12-17 18:31:35 -0800497 mActivity.getCameraAppUI().transitionToIntentReviewLayout();
Doris Liud31cdfe2013-05-14 11:31:19 -0700498 pauseFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800499 }
500
501 protected void hidePostCaptureAlert() {
Doris Liu36e56fb2013-09-11 17:38:08 -0700502 if (mDecodeTaskForReview != null) {
503 mDecodeTaskForReview.cancel(true);
504 }
Doris Liud31cdfe2013-05-14 11:31:19 -0700505 resumeFaceDetection();
Michael Kolbd6954f32013-03-08 20:43:01 -0800506 }
507
508 public void setDisplayOrientation(int orientation) {
509 if (mFaceView != null) {
510 mFaceView.setDisplayOrientation(orientation);
511 }
512 }
513
Doris Liuf9e4f8f2013-12-04 18:04:22 -0800514 private class ZoomChangeListener implements PreviewOverlay.OnZoomChangedListener {
Michael Kolbd6954f32013-03-08 20:43:01 -0800515 @Override
Sol Boucher2192fba2014-08-19 17:24:07 -0700516 public void onZoomValueChanged(float ratio) {
517 mController.onZoomChanged(ratio);
Michael Kolbd6954f32013-03-08 20:43:01 -0800518 }
519
520 @Override
521 public void onZoomStart() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800522 }
523
524 @Override
525 public void onZoomEnd() {
Michael Kolbd6954f32013-03-08 20:43:01 -0800526 }
527 }
528
Doris Liu6432cd62013-06-13 17:20:31 -0700529 public void setSwipingEnabled(boolean enable) {
530 mActivity.setSwipingEnabled(enable);
Michael Kolbd6954f32013-03-08 20:43:01 -0800531 }
532
Michael Kolbd6954f32013-03-08 20:43:01 -0800533 public void onPause() {
Sascha Haeberling1d943642014-05-19 11:56:53 -0700534 if (mFaceView != null) {
535 mFaceView.clear();
536 }
Doris Liudb8f9752014-05-12 15:25:13 -0700537 if (mDialog != null) {
538 mDialog.dismiss();
539 }
Alan Newberger73514152014-09-10 15:03:27 -0700540 // recalculate aspect ratio when restarting.
541 mAspectRatio = 0.0f;
Michael Kolbd6954f32013-03-08 20:43:01 -0800542 }
543
Michael Kolbd6954f32013-03-08 20:43:01 -0800544 public void clearFaces() {
Marco Nelissen0744e4a2013-11-22 01:47:37 +0000545 if (mFaceView != null) {
546 mFaceView.clear();
547 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800548 }
549
Michael Kolbd6954f32013-03-08 20:43:01 -0800550 public void pauseFaceDetection() {
Sascha Haeberling1d943642014-05-19 11:56:53 -0700551 if (mFaceView != null) {
552 mFaceView.pause();
553 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800554 }
555
Michael Kolbd6954f32013-03-08 20:43:01 -0800556 public void resumeFaceDetection() {
Sascha Haeberling1d943642014-05-19 11:56:53 -0700557 if (mFaceView != null) {
558 mFaceView.resume();
559 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800560 }
561
562 public void onStartFaceDetection(int orientation, boolean mirror) {
Doris Liud27ea7b2014-02-25 11:46:11 -0800563 if (mFaceView != null) {
564 mFaceView.clear();
565 mFaceView.setVisibility(View.VISIBLE);
566 mFaceView.setDisplayOrientation(orientation);
567 mFaceView.setMirror(mirror);
568 mFaceView.resume();
569 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800570 }
571
572 @Override
Sol Boucher5a344962014-06-17 14:05:08 -0700573 public void onFaceDetection(Face[] faces, CameraAgent.CameraProxy camera) {
Doris Liud27ea7b2014-02-25 11:46:11 -0800574 if (mFaceView != null) {
575 mFaceView.setFaces(faces);
576 }
Michael Kolbd6954f32013-03-08 20:43:01 -0800577 }
578
Michael Kolbd6954f32013-03-08 20:43:01 -0800579}