OSDN Git Service

Fix the flash mode transition in video mode
[android-x86/packages-apps-Camera2.git] / src / com / android / camera / PhotoUI.java
1 /*
2  * Copyright (C) 2012 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
18 package com.android.camera;
19
20 import android.app.AlertDialog;
21 import android.content.DialogInterface;
22 import android.graphics.Bitmap;
23 import android.graphics.Color;
24 import android.graphics.Matrix;
25 import android.graphics.SurfaceTexture;
26 import android.graphics.drawable.ColorDrawable;
27 import android.hardware.Camera;
28 import android.hardware.Camera.Face;
29 import android.os.AsyncTask;
30 import android.util.Log;
31 import android.view.Gravity;
32 import android.view.TextureView;
33 import android.view.View;
34 import android.view.View.OnClickListener;
35 import android.view.View.OnLayoutChangeListener;
36 import android.view.ViewGroup;
37 import android.view.ViewStub;
38 import android.widget.FrameLayout.LayoutParams;
39 import android.widget.ImageView;
40 import android.widget.PopupWindow;
41 import android.widget.Toast;
42
43 import com.android.camera.CameraPreference.OnPreferenceChangedListener;
44 import com.android.camera.FocusOverlayManager.FocusUI;
45 import com.android.camera.ui.ModuleSwitcher;
46 import com.android.camera.util.ApiHelper;
47 import com.android.camera.ui.AbstractSettingPopup;
48 import com.android.camera.ui.CameraControls;
49 import com.android.camera.ui.CameraRootView;
50 import com.android.camera.ui.CountDownView;
51 import com.android.camera.ui.CountDownView.OnCountDownFinishedListener;
52 import com.android.camera.ui.FaceView;
53 import com.android.camera.ui.FocusIndicator;
54 import com.android.camera.ui.PieRenderer;
55 import com.android.camera.ui.PieRenderer.PieListener;
56 import com.android.camera.ui.RenderOverlay;
57 import com.android.camera.ui.ZoomRenderer;
58 import com.android.camera.util.CameraUtil;
59 import com.android.camera2.R;
60
61 import java.util.List;
62
63 public class PhotoUI implements PieListener,
64     PreviewGestures.SingleTapListener,
65     FocusUI, TextureView.SurfaceTextureListener,
66     LocationManager.Listener, CameraRootView.MyDisplayListener,
67     CameraManager.CameraFaceDetectionCallback {
68
69     private static final String TAG = "CAM_UI";
70     private static final int DOWN_SAMPLE_FACTOR = 4;
71     private final AnimationManager mAnimationManager;
72     private CameraActivity mActivity;
73     private PhotoController mController;
74     private PreviewGestures mGestures;
75
76     private View mRootView;
77     private SurfaceTexture mSurfaceTexture;
78
79     private PopupWindow mPopup;
80     private ShutterButton mShutterButton;
81     private CountDownView mCountDownView;
82
83     private FaceView mFaceView;
84     private RenderOverlay mRenderOverlay;
85     private View mReviewCancelButton;
86     private View mReviewDoneButton;
87     private View mReviewRetakeButton;
88
89     private View mMenuButton;
90     private PhotoMenu mMenu;
91     private ModuleSwitcher mSwitcher;
92     private CameraControls mCameraControls;
93     private AlertDialog mLocationDialog;
94
95     // Small indicators which show the camera settings in the viewfinder.
96     private OnScreenIndicators mOnScreenIndicators;
97
98     private PieRenderer mPieRenderer;
99     private ZoomRenderer mZoomRenderer;
100     private Toast mNotSelectableToast;
101
102     private int mZoomMax;
103     private List<Integer> mZoomRatios;
104
105     private int mPreviewWidth = 0;
106     private int mPreviewHeight = 0;
107     private float mSurfaceTextureUncroppedWidth;
108     private float mSurfaceTextureUncroppedHeight;
109
110     private ImageView mPreviewThumb;
111     private View mFlashOverlay;
112
113     private SurfaceTextureSizeChangedListener mSurfaceTextureSizeListener;
114     private TextureView mTextureView;
115     private Matrix mMatrix = null;
116     private float mAspectRatio = 4f / 3f;
117
118     public interface SurfaceTextureSizeChangedListener {
119         public void onSurfaceTextureSizeChanged(int uncroppedWidth, int uncroppedHeight);
120     }
121
122     private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() {
123         @Override
124         public void onLayoutChange(View v, int left, int top, int right,
125                 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
126             int width = right - left;
127             int height = bottom - top;
128             // Full-screen preview
129             int w = width;
130             int h = height;
131             if (CameraUtil.getDisplayRotation(mActivity) % 180 != 0) {
132                 w = height;
133                 h = width;
134             }
135             if (mPreviewWidth != width || mPreviewHeight != height) {
136                 mPreviewWidth = width;
137                 mPreviewHeight = height;
138                 setTransformMatrix(width, height);
139                 mController.onScreenSizeChanged(width, height, w, h);
140             }
141         }
142     };
143
144     private class DecodeTask extends AsyncTask<Integer, Void, Bitmap> {
145         private final byte [] mData;
146         private int mOrientation;
147         private boolean mMirror;
148
149         public DecodeTask(byte[] data, int orientation, boolean mirror) {
150             mData = data;
151             mOrientation = orientation;
152             mMirror = mirror;
153         }
154
155         @Override
156         protected Bitmap doInBackground(Integer... params) {
157             // Decode image in background.
158             Bitmap bitmap = CameraUtil.downSample(mData, DOWN_SAMPLE_FACTOR);
159             if (mOrientation != 0 || mMirror) {
160                 Matrix m = new Matrix();
161                 m.preRotate(mOrientation);
162                 if (mMirror) {
163                     // Flip horizontally
164                     m.setScale(-1f, 1f);
165                 }
166                 return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m,
167                         false);
168             }
169             return bitmap;
170         }
171
172         @Override
173         protected void onPostExecute(Bitmap bitmap) {
174             mPreviewThumb.setImageBitmap(bitmap);
175             mAnimationManager.startCaptureAnimation(mPreviewThumb);
176         }
177     }
178
179     public PhotoUI(CameraActivity activity, PhotoController controller, View parent) {
180         mActivity = activity;
181         mController = controller;
182         mRootView = parent;
183
184         mActivity.getLayoutInflater().inflate(R.layout.photo_module,
185                 (ViewGroup) mRootView, true);
186         mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
187         mFlashOverlay = mRootView.findViewById(R.id.flash_overlay);
188         // display the view
189         mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content);
190         mTextureView.setSurfaceTextureListener(this);
191         mTextureView.addOnLayoutChangeListener(mLayoutListener);
192         initIndicators();
193
194         mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
195         mSwitcher = (ModuleSwitcher) mRootView.findViewById(R.id.camera_switcher);
196         mSwitcher.setCurrentIndex(ModuleSwitcher.PHOTO_MODULE_INDEX);
197         mSwitcher.setSwitchListener(mActivity);
198         mMenuButton = mRootView.findViewById(R.id.menu);
199         if (ApiHelper.HAS_FACE_DETECTION) {
200             ViewStub faceViewStub = (ViewStub) mRootView
201                     .findViewById(R.id.face_view_stub);
202             if (faceViewStub != null) {
203                 faceViewStub.inflate();
204                 mFaceView = (FaceView) mRootView.findViewById(R.id.face_view);
205                 setSurfaceTextureSizeChangedListener(mFaceView);
206             }
207         }
208         mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls);
209         ((CameraRootView) mRootView).setDisplayChangeListener(this);
210         mAnimationManager = new AnimationManager();
211     }
212
213     public void setSurfaceTextureSizeChangedListener(SurfaceTextureSizeChangedListener listener) {
214         mSurfaceTextureSizeListener = listener;
215     }
216
217     private void setTransformMatrix(int width, int height) {
218         mMatrix = mTextureView.getTransform(mMatrix);
219         float scaleX = 1f, scaleY = 1f;
220         float scaledTextureWidth, scaledTextureHeight;
221         if (width > height) {
222             scaledTextureWidth = Math.max(width,
223                     (int) (height * mAspectRatio));
224             scaledTextureHeight = Math.max(height,
225                     (int)(width / mAspectRatio));
226         } else {
227             scaledTextureWidth = Math.max(width,
228                     (int) (height / mAspectRatio));
229             scaledTextureHeight = Math.max(height,
230                     (int) (width * mAspectRatio));
231         }
232
233         if (mSurfaceTextureUncroppedWidth != scaledTextureWidth ||
234                 mSurfaceTextureUncroppedHeight != scaledTextureHeight) {
235             mSurfaceTextureUncroppedWidth = scaledTextureWidth;
236             mSurfaceTextureUncroppedHeight = scaledTextureHeight;
237             if (mSurfaceTextureSizeListener != null) {
238                 mSurfaceTextureSizeListener.onSurfaceTextureSizeChanged(
239                         (int) mSurfaceTextureUncroppedWidth, (int) mSurfaceTextureUncroppedHeight);
240             }
241         }
242         scaleX = scaledTextureWidth / width;
243         scaleY = scaledTextureHeight / height;
244         mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2);
245         mTextureView.setTransform(mMatrix);
246     }
247
248     @Override
249     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
250         Log.v(TAG, "SurfaceTexture ready.");
251         mSurfaceTexture = surface;
252         mController.onPreviewUIReady();
253     }
254
255     @Override
256     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
257         // Ignored, Camera does all the work for us
258     }
259
260     @Override
261     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
262         mSurfaceTexture = null;
263         mController.onPreviewUIDestroyed();
264         Log.w(TAG, "SurfaceTexture destroyed");
265         return true;
266     }
267
268     @Override
269     public void onSurfaceTextureUpdated(SurfaceTexture surface) {
270         // Do nothing.
271     }
272
273     public View getRootView() {
274         return mRootView;
275     }
276
277     private void initIndicators() {
278         mOnScreenIndicators = new OnScreenIndicators(mActivity,
279                 mRootView.findViewById(R.id.on_screen_indicators));
280     }
281
282     public void onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs,
283             Camera.Parameters params, OnPreferenceChangedListener listener) {
284         if (mPieRenderer == null) {
285             mPieRenderer = new PieRenderer(mActivity);
286             mPieRenderer.setPieListener(this);
287             mRenderOverlay.addRenderer(mPieRenderer);
288         }
289
290         if (mMenu == null) {
291             mMenu = new PhotoMenu(mActivity, this, mPieRenderer);
292             mMenu.setListener(listener);
293         }
294         mMenu.initialize(prefGroup);
295
296         if (mZoomRenderer == null) {
297             mZoomRenderer = new ZoomRenderer(mActivity);
298             mRenderOverlay.addRenderer(mZoomRenderer);
299         }
300
301         if (mGestures == null) {
302             // this will handle gesture disambiguation and dispatching
303             mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
304             mRenderOverlay.setGestures(mGestures);
305         }
306         mGestures.setZoomEnabled(params.isZoomSupported());
307         mGestures.setRenderOverlay(mRenderOverlay);
308         mRenderOverlay.requestLayout();
309
310         initializeZoom(params);
311         updateOnScreenIndicators(params, prefGroup, prefs);
312     }
313
314     public void animateCapture(final byte[] jpegData, int orientation, boolean mirror) {
315         // Decode jpeg byte array and then animate the jpeg
316         DecodeTask task = new DecodeTask(jpegData, orientation, mirror);
317         task.execute();
318     }
319
320     private void openMenu() {
321         if (mPieRenderer != null) {
322             // If autofocus is not finished, cancel autofocus so that the
323             // subsequent touch can be handled by PreviewGestures
324             if (mController.getCameraState() == PhotoController.FOCUSING) {
325                     mController.cancelAutoFocus();
326             }
327             mPieRenderer.showInCenter();
328         }
329     }
330
331     public void initializeControlByIntent() {
332         mPreviewThumb = (ImageView) mRootView.findViewById(R.id.preview_thumb);
333         mPreviewThumb.setOnClickListener(new OnClickListener() {
334             @Override
335             public void onClick(View v) {
336                 mActivity.gotoGallery();
337             }
338         });
339         mMenuButton = mRootView.findViewById(R.id.menu);
340         mMenuButton.setOnClickListener(new OnClickListener() {
341             @Override
342             public void onClick(View v) {
343                 openMenu();
344             }
345         });
346         if (mController.isImageCaptureIntent()) {
347             hideSwitcher();
348             ViewGroup cameraControls = (ViewGroup) mRootView.findViewById(R.id.camera_controls);
349             mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls);
350
351             mReviewDoneButton = mRootView.findViewById(R.id.btn_done);
352             mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel);
353             mReviewRetakeButton = mRootView.findViewById(R.id.btn_retake);
354             mReviewCancelButton.setVisibility(View.VISIBLE);
355
356             mReviewDoneButton.setOnClickListener(new OnClickListener() {
357                 @Override
358                 public void onClick(View v) {
359                     mController.onCaptureDone();
360                 }
361             });
362             mReviewCancelButton.setOnClickListener(new OnClickListener() {
363                 @Override
364                 public void onClick(View v) {
365                     mController.onCaptureCancelled();
366                 }
367             });
368
369             mReviewRetakeButton.setOnClickListener(new OnClickListener() {
370                 @Override
371                 public void onClick(View v) {
372                     mController.onCaptureRetake();
373                 }
374             });
375         }
376     }
377
378     public void hideUI() {
379         mCameraControls.setVisibility(View.INVISIBLE);
380         mSwitcher.closePopup();
381     }
382
383     public void showUI() {
384         mCameraControls.setVisibility(View.VISIBLE);
385     }
386
387     public void hideSwitcher() {
388         mSwitcher.closePopup();
389         mSwitcher.setVisibility(View.INVISIBLE);
390     }
391
392     public void showSwitcher() {
393         mSwitcher.setVisibility(View.VISIBLE);
394     }
395     // called from onResume but only the first time
396     public  void initializeFirstTime() {
397         // Initialize shutter button.
398         mShutterButton.setImageResource(R.drawable.btn_new_shutter);
399         mShutterButton.setOnShutterButtonListener(mController);
400         mShutterButton.setVisibility(View.VISIBLE);
401     }
402
403     // called from onResume every other time
404     public void initializeSecondTime(Camera.Parameters params) {
405         initializeZoom(params);
406         if (mController.isImageCaptureIntent()) {
407             hidePostCaptureAlert();
408         }
409         if (mMenu != null) {
410             mMenu.reloadPreferences();
411         }
412     }
413
414     public void showLocationDialog() {
415         mLocationDialog = new AlertDialog.Builder(mActivity)
416                 .setTitle(R.string.remember_location_title)
417                 .setMessage(R.string.remember_location_prompt)
418                 .setPositiveButton(R.string.remember_location_yes,
419                         new DialogInterface.OnClickListener() {
420                             @Override
421                             public void onClick(DialogInterface dialog, int arg1) {
422                                 mController.enableRecordingLocation(true);
423                                 mLocationDialog = null;
424                             }
425                         })
426                 .setNegativeButton(R.string.remember_location_no,
427                         new DialogInterface.OnClickListener() {
428                             @Override
429                             public void onClick(DialogInterface dialog, int arg1) {
430                                 dialog.cancel();
431                             }
432                         })
433                 .setOnCancelListener(new DialogInterface.OnCancelListener() {
434                     @Override
435                     public void onCancel(DialogInterface dialog) {
436                         mController.enableRecordingLocation(false);
437                         mLocationDialog = null;
438                     }
439                 })
440                 .show();
441     }
442
443     public void initializeZoom(Camera.Parameters params) {
444         if ((params == null) || !params.isZoomSupported()
445                 || (mZoomRenderer == null)) return;
446         mZoomMax = params.getMaxZoom();
447         mZoomRatios = params.getZoomRatios();
448         // Currently we use immediate zoom for fast zooming to get better UX and
449         // there is no plan to take advantage of the smooth zoom.
450         if (mZoomRenderer != null) {
451             mZoomRenderer.setZoomMax(mZoomMax);
452             mZoomRenderer.setZoom(params.getZoom());
453             mZoomRenderer.setZoomValue(mZoomRatios.get(params.getZoom()));
454             mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener());
455         }
456     }
457
458     @Override
459     public void showGpsOnScreenIndicator(boolean hasSignal) { }
460
461     @Override
462     public void hideGpsOnScreenIndicator() { }
463
464     public void overrideSettings(final String ... keyvalues) {
465         mMenu.overrideSettings(keyvalues);
466     }
467
468     public void updateOnScreenIndicators(Camera.Parameters params,
469             PreferenceGroup group, ComboPreferences prefs) {
470         if (params == null) return;
471         mOnScreenIndicators.updateSceneOnScreenIndicator(params.getSceneMode());
472         mOnScreenIndicators.updateExposureOnScreenIndicator(params,
473                 CameraSettings.readExposure(prefs));
474         mOnScreenIndicators.updateFlashOnScreenIndicator(params.getFlashMode());
475         int wbIndex = 2;
476         ListPreference pref = group.findPreference(CameraSettings.KEY_WHITE_BALANCE);
477         if (pref != null) {
478             wbIndex = pref.getCurrentIndex();
479         }
480         mOnScreenIndicators.updateWBIndicator(wbIndex);
481         boolean location = RecordLocationPreference.get(
482                 prefs, mActivity.getContentResolver());
483         mOnScreenIndicators.updateLocationIndicator(location);
484     }
485
486     public void setCameraState(int state) {
487     }
488
489     public void animateFlash() {
490         mAnimationManager.startFlashAnimation(mFlashOverlay);
491     }
492
493     public void enableGestures(boolean enable) {
494         if (mGestures != null) {
495             mGestures.setEnabled(enable);
496         }
497     }
498
499     // forward from preview gestures to controller
500     @Override
501     public void onSingleTapUp(View view, int x, int y) {
502         mController.onSingleTapUp(view, x, y);
503     }
504
505     public boolean onBackPressed() {
506         if (mPieRenderer != null && mPieRenderer.showsItems()) {
507             mPieRenderer.hide();
508             return true;
509         }
510         // In image capture mode, back button should:
511         // 1) if there is any popup, dismiss them, 2) otherwise, get out of
512         // image capture
513         if (mController.isImageCaptureIntent()) {
514             mController.onCaptureCancelled();
515             return true;
516         } else if (!mController.isCameraIdle()) {
517             // ignore backs while we're taking a picture
518             return true;
519         } else {
520             return false;
521         }
522     }
523
524     public void onPreviewFocusChanged(boolean previewFocused) {
525         if (previewFocused) {
526             showUI();
527         } else {
528             hideUI();
529         }
530         if (mFaceView != null) {
531             mFaceView.setBlockDraw(!previewFocused);
532         }
533         if (mGestures != null) {
534             mGestures.setEnabled(previewFocused);
535         }
536         if (mRenderOverlay != null) {
537             // this can not happen in capture mode
538             mRenderOverlay.setVisibility(previewFocused ? View.VISIBLE : View.GONE);
539         }
540         if (mPieRenderer != null) {
541             mPieRenderer.setBlockFocus(!previewFocused);
542         }
543         setShowMenu(previewFocused);
544         if (!previewFocused && mCountDownView != null) mCountDownView.cancelCountDown();
545     }
546
547     public void showPopup(AbstractSettingPopup popup) {
548         hideUI();
549
550         if (mPopup == null) {
551             mPopup = new PopupWindow(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
552             mPopup.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
553             mPopup.setOutsideTouchable(true);
554             mPopup.setFocusable(true);
555             mPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
556                 @Override
557                 public void onDismiss() {
558                     mPopup = null;
559                     mMenu.popupDismissed();
560                     showUI();
561                 }
562             });
563         }
564         popup.setVisibility(View.VISIBLE);
565         mPopup.setContentView(popup);
566         mPopup.showAtLocation(mRootView, Gravity.CENTER, 0, 0);
567     }
568
569     public void dismissPopup() {
570         if (mPopup != null && mPopup.isShowing()) {
571             mPopup.dismiss();
572         }
573     }
574
575     public void onShowSwitcherPopup() {
576         if (mPieRenderer != null && mPieRenderer.showsItems()) {
577             mPieRenderer.hide();
578         }
579     }
580
581     private void setShowMenu(boolean show) {
582         if (mOnScreenIndicators != null) {
583             mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE);
584         }
585         if (mMenuButton != null) {
586             mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE);
587         }
588     }
589
590     public boolean collapseCameraControls() {
591         // Remove all the popups/dialog boxes
592         boolean ret = false;
593         if (mPopup != null) {
594             dismissPopup();
595             ret = true;
596         }
597         onShowSwitcherPopup();
598         return ret;
599     }
600
601     protected void showPostCaptureAlert() {
602         mOnScreenIndicators.setVisibility(View.GONE);
603         mMenuButton.setVisibility(View.GONE);
604         CameraUtil.fadeIn(mReviewDoneButton);
605         mShutterButton.setVisibility(View.INVISIBLE);
606         CameraUtil.fadeIn(mReviewRetakeButton);
607         pauseFaceDetection();
608     }
609
610     protected void hidePostCaptureAlert() {
611         mOnScreenIndicators.setVisibility(View.VISIBLE);
612         mMenuButton.setVisibility(View.VISIBLE);
613         CameraUtil.fadeOut(mReviewDoneButton);
614         mShutterButton.setVisibility(View.VISIBLE);
615         CameraUtil.fadeOut(mReviewRetakeButton);
616         resumeFaceDetection();
617     }
618
619     public void setDisplayOrientation(int orientation) {
620         if (mFaceView != null) {
621             mFaceView.setDisplayOrientation(orientation);
622         }
623     }
624
625     // shutter button handling
626
627     public boolean isShutterPressed() {
628         return mShutterButton.isPressed();
629     }
630
631     /**
632      * Enables or disables the shutter button.
633      */
634     public void enableShutter(boolean enabled) {
635         if (mShutterButton != null) {
636             mShutterButton.setEnabled(enabled);
637         }
638     }
639
640     public void pressShutterButton() {
641         if (mShutterButton.isInTouchMode()) {
642             mShutterButton.requestFocusFromTouch();
643         } else {
644             mShutterButton.requestFocus();
645         }
646         mShutterButton.setPressed(true);
647     }
648
649     private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
650         @Override
651         public void onZoomValueChanged(int index) {
652             int newZoom = mController.onZoomChanged(index);
653             if (mZoomRenderer != null) {
654                 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom));
655             }
656         }
657
658         @Override
659         public void onZoomStart() {
660             if (mPieRenderer != null) {
661                 mPieRenderer.setBlockFocus(true);
662             }
663         }
664
665         @Override
666         public void onZoomEnd() {
667             if (mPieRenderer != null) {
668                 mPieRenderer.setBlockFocus(false);
669             }
670         }
671     }
672
673     @Override
674     public void onPieOpened(int centerX, int centerY) {
675         setSwipingEnabled(false);
676         if (mFaceView != null) {
677             mFaceView.setBlockDraw(true);
678         }
679     }
680
681     @Override
682     public void onPieClosed() {
683         setSwipingEnabled(true);
684         if (mFaceView != null) {
685             mFaceView.setBlockDraw(false);
686         }
687     }
688
689     public void setSwipingEnabled(boolean enable) {
690         mActivity.setSwipingEnabled(enable);
691     }
692
693     public SurfaceTexture getSurfaceTexture() {
694         return mSurfaceTexture;
695     }
696
697     // Countdown timer
698
699     private void initializeCountDown() {
700         mActivity.getLayoutInflater().inflate(R.layout.count_down_to_capture,
701                 (ViewGroup) mRootView, true);
702         mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture));
703         mCountDownView.setCountDownFinishedListener((OnCountDownFinishedListener) mController);
704     }
705
706     public boolean isCountingDown() {
707         return mCountDownView != null && mCountDownView.isCountingDown();
708     }
709
710     public void cancelCountDown() {
711         if (mCountDownView == null) return;
712         mCountDownView.cancelCountDown();
713     }
714
715     public void startCountDown(int sec, boolean playSound) {
716         if (mCountDownView == null) initializeCountDown();
717         mCountDownView.startCountDown(sec, playSound);
718     }
719
720     public void showPreferencesToast() {
721         if (mNotSelectableToast == null) {
722             String str = mActivity.getResources().getString(R.string.not_selectable_in_scene_mode);
723             mNotSelectableToast = Toast.makeText(mActivity, str, Toast.LENGTH_SHORT);
724         }
725         mNotSelectableToast.show();
726     }
727
728     public void onPause() {
729         cancelCountDown();
730
731         // Clear UI.
732         collapseCameraControls();
733         if (mFaceView != null) mFaceView.clear();
734
735         if (mLocationDialog != null && mLocationDialog.isShowing()) {
736             mLocationDialog.dismiss();
737         }
738         mLocationDialog = null;
739         mPreviewWidth = 0;
740         mPreviewHeight = 0;
741     }
742
743     // focus UI implementation
744
745     private FocusIndicator getFocusIndicator() {
746         return (mFaceView != null && mFaceView.faceExists()) ? mFaceView : mPieRenderer;
747     }
748
749     @Override
750     public boolean hasFaces() {
751         return (mFaceView != null && mFaceView.faceExists());
752     }
753
754     public void clearFaces() {
755         if (mFaceView != null) mFaceView.clear();
756     }
757
758     @Override
759     public void clearFocus() {
760         FocusIndicator indicator = getFocusIndicator();
761         if (indicator != null) indicator.clear();
762     }
763
764     @Override
765     public void setFocusPosition(int x, int y) {
766         mPieRenderer.setFocus(x, y);
767     }
768
769     @Override
770     public void onFocusStarted() {
771         getFocusIndicator().showStart();
772     }
773
774     @Override
775     public void onFocusSucceeded(boolean timeout) {
776         getFocusIndicator().showSuccess(timeout);
777     }
778
779     @Override
780     public void onFocusFailed(boolean timeout) {
781         getFocusIndicator().showFail(timeout);
782     }
783
784     @Override
785     public void pauseFaceDetection() {
786         if (mFaceView != null) mFaceView.pause();
787     }
788
789     @Override
790     public void resumeFaceDetection() {
791         if (mFaceView != null) mFaceView.resume();
792     }
793
794     public void onStartFaceDetection(int orientation, boolean mirror) {
795         mFaceView.clear();
796         mFaceView.setVisibility(View.VISIBLE);
797         mFaceView.setDisplayOrientation(orientation);
798         mFaceView.setMirror(mirror);
799         mFaceView.resume();
800     }
801
802     @Override
803     public void onFaceDetection(Face[] faces, CameraManager.CameraProxy camera) {
804         mFaceView.setFaces(faces);
805     }
806
807     @Override
808     public void onDisplayChanged() {
809         mCameraControls.checkLayoutFlip();
810         mController.updateCameraOrientation();
811     }
812
813 }