OSDN Git Service

Merge "Save video using MediaSaveService." into gb-ub-photos-bryce
[android-x86/packages-apps-Camera2.git] / src / com / android / camera / PhotoUI.java
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 package com.android.camera;
19
20 import android.hardware.Camera;
21 import android.hardware.Camera.Face;
22 import android.hardware.Camera.FaceDetectionListener;
23 import android.hardware.Camera.Parameters;
24 import android.util.Log;
25 import android.view.Gravity;
26 import android.view.MotionEvent;
27 import android.view.SurfaceHolder;
28 import android.view.View;
29 import android.view.View.OnClickListener;
30 import android.view.View.OnLayoutChangeListener;
31 import android.view.ViewGroup;
32 import android.view.ViewStub;
33 import android.widget.FrameLayout;
34 import android.widget.FrameLayout.LayoutParams;
35 import android.widget.ImageView;
36 import android.widget.Toast;
37
38 import com.android.camera.CameraPreference.OnPreferenceChangedListener;
39 import com.android.camera.FocusOverlayManager.FocusUI;
40 import com.android.camera.ui.AbstractSettingPopup;
41 import com.android.camera.ui.CountDownView;
42 import com.android.camera.ui.CountDownView.OnCountDownFinishedListener;
43 import com.android.camera.ui.FaceView;
44 import com.android.camera.ui.FocusIndicator;
45 import com.android.camera.ui.PieRenderer;
46 import com.android.camera.ui.PieRenderer.PieListener;
47 import com.android.camera.ui.RenderOverlay;
48 import com.android.camera.ui.ZoomRenderer;
49 import com.android.gallery3d.R;
50 import com.android.gallery3d.common.ApiHelper;
51
52 import java.util.List;
53
54 public class PhotoUI implements PieListener,
55     SurfaceHolder.Callback,
56     PreviewGestures.SingleTapListener,
57     FocusUI,
58     LocationManager.Listener,
59     FaceDetectionListener,
60     PreviewGestures.SwipeListener {
61
62     private static final String TAG = "CAM_UI";
63
64     private CameraActivity mActivity;
65     private PhotoController mController;
66     private PreviewGestures mGestures;
67
68     private View mRootView;
69     private Object mSurfaceTexture;
70     private volatile SurfaceHolder mSurfaceHolder;
71
72     private AbstractSettingPopup mPopup;
73     private ShutterButton mShutterButton;
74     private CountDownView mCountDownView;
75
76     private FaceView mFaceView;
77     private RenderOverlay mRenderOverlay;
78     private View mReviewCancelButton;
79     private View mReviewDoneButton;
80     private View mReviewRetakeButton;
81
82     private View mMenuButton;
83     private View mBlocker;
84     private PhotoMenu mMenu;
85
86     // Small indicators which show the camera settings in the viewfinder.
87     private ImageView mExposureIndicator;
88     private ImageView mFlashIndicator;
89     private ImageView mSceneIndicator;
90     private ImageView mHdrIndicator;
91     // A view group that contains all the small indicators.
92     private View mOnScreenIndicators;
93
94     private PieRenderer mPieRenderer;
95     private ZoomRenderer mZoomRenderer;
96     private Toast mNotSelectableToast;
97
98     private int mZoomMax;
99     private List<Integer> mZoomRatios;
100
101     private int mPreviewWidth = 0;
102     private int mPreviewHeight = 0;
103
104     private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() {
105         @Override
106         public void onLayoutChange(View v, int left, int top, int right,
107                 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
108             int width = right - left;
109             int height = bottom - top;
110             // Full-screen screennail
111             int w = width;
112             int h = height;
113             if (Util.getDisplayRotation(mActivity) % 180 != 0) {
114                 w = height;
115                 h = width;
116             }
117             if (mPreviewWidth != w || mPreviewHeight != h) {
118                 mPreviewWidth = w;
119                 mPreviewHeight = h;
120                 mController.onScreenSizeChanged(width, height, w, h);
121             }
122         }
123     };
124
125     public PhotoUI(CameraActivity activity, PhotoController controller, View parent) {
126         mActivity = activity;
127         mController = controller;
128         mRootView = parent;
129
130         mActivity.getLayoutInflater().inflate(R.layout.photo_module,
131                 (ViewGroup) mRootView, true);
132         mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
133
134         initIndicators();
135         mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture));
136         mCountDownView.setCountDownFinishedListener((OnCountDownFinishedListener) mController);
137
138         if (ApiHelper.HAS_FACE_DETECTION) {
139             ViewStub faceViewStub = (ViewStub) mRootView
140                     .findViewById(R.id.face_view_stub);
141             if (faceViewStub != null) {
142                 faceViewStub.inflate();
143                 mFaceView = (FaceView) mRootView.findViewById(R.id.face_view);
144             }
145         }
146
147     }
148
149     public View getRootView() {
150         return mRootView;
151     }
152
153     private void initIndicators() {
154         mOnScreenIndicators = mActivity.findViewById(R.id.on_screen_indicators);
155         mExposureIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_exposure_indicator);
156         mFlashIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_flash_indicator);
157         mSceneIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_scenemode_indicator);
158         mHdrIndicator = (ImageView) mOnScreenIndicators.findViewById(R.id.menu_hdr_indicator);
159     }
160
161     public void onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs,
162             Camera.Parameters params, OnPreferenceChangedListener listener) {
163         if (mPieRenderer == null) {
164             mPieRenderer = new PieRenderer(mActivity);
165             mPieRenderer.setPieListener(this);
166             mRenderOverlay.addRenderer(mPieRenderer);
167         }
168         if (mMenu == null) {
169             mMenu = new PhotoMenu(mActivity, this, mPieRenderer);
170             mMenu.setListener(listener);
171         }
172         mMenu.initialize(prefGroup);
173
174         if (mZoomRenderer == null) {
175             mZoomRenderer = new ZoomRenderer(mActivity);
176             mRenderOverlay.addRenderer(mZoomRenderer);
177         }
178         if (mGestures == null) {
179             // this will handle gesture disambiguation and dispatching
180             mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer,
181                     this);
182         }
183         mGestures.reset();
184         mGestures.setRenderOverlay(mRenderOverlay);
185         mGestures.addTouchReceiver(mMenuButton);
186         mGestures.addUnclickableArea(mBlocker);
187         // make sure to add touch targets for image capture
188         if (mController.isImageCaptureIntent()) {
189             if (mReviewCancelButton != null) {
190                 mGestures.addTouchReceiver(mReviewCancelButton);
191             }
192             if (mReviewDoneButton != null) {
193                 mGestures.addTouchReceiver(mReviewDoneButton);
194             }
195         }
196         mRenderOverlay.requestLayout();
197
198         initializeZoom(params);
199         updateOnScreenIndicators(params, prefs);
200     }
201
202     private void openMenu() {
203         if (mPieRenderer != null) {
204             // If autofocus is not finished, cancel autofocus so that the
205             // subsequent touch can be handled by PreviewGestures
206             if (mController.getCameraState() == PhotoController.FOCUSING) {
207                     mController.cancelAutoFocus();
208             }
209             mPieRenderer.showInCenter();
210         }
211     }
212
213     public void initializeControlByIntent() {
214         mBlocker = mActivity.findViewById(R.id.blocker);
215         mMenuButton = mActivity.findViewById(R.id.menu);
216         mMenuButton.setOnClickListener(new OnClickListener() {
217             @Override
218             public void onClick(View v) {
219                 openMenu();
220             }
221         });
222         if (mController.isImageCaptureIntent()) {
223             mActivity.hideSwitcher();
224             ViewGroup cameraControls = (ViewGroup) mActivity.findViewById(R.id.camera_controls);
225             mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls);
226
227             mReviewDoneButton = mActivity.findViewById(R.id.btn_done);
228             mReviewCancelButton = mActivity.findViewById(R.id.btn_cancel);
229             mReviewRetakeButton = mActivity.findViewById(R.id.btn_retake);
230             mReviewCancelButton.setVisibility(View.VISIBLE);
231
232             mReviewDoneButton.setOnClickListener(new OnClickListener() {
233                 @Override
234                 public void onClick(View v) {
235                     mController.onCaptureDone();
236                 }
237             });
238             mReviewCancelButton.setOnClickListener(new OnClickListener() {
239                 @Override
240                 public void onClick(View v) {
241                     mController.onCaptureCancelled();
242                 }
243             });
244
245             mReviewRetakeButton.setOnClickListener(new OnClickListener() {
246                 @Override
247                 public void onClick(View v) {
248                     mController.onCaptureRetake();
249                 }
250             });
251         }
252     }
253
254     // called from onResume but only the first time
255     public  void initializeFirstTime() {
256         // Initialize shutter button.
257         mShutterButton = mActivity.getShutterButton();
258         mShutterButton.setImageResource(R.drawable.btn_new_shutter);
259         mShutterButton.setOnShutterButtonListener(mController);
260         mShutterButton.setVisibility(View.VISIBLE);
261         mRootView.addOnLayoutChangeListener(mLayoutListener);
262     }
263
264     // called from onResume every other time
265     public void initializeSecondTime(Camera.Parameters params) {
266         initializeZoom(params);
267         if (mController.isImageCaptureIntent()) {
268             hidePostCaptureAlert();
269         }
270         if (mMenu != null) {
271             mMenu.reloadPreferences();
272         }
273         mRootView.addOnLayoutChangeListener(mLayoutListener);
274     }
275
276     public void initializeZoom(Camera.Parameters params) {
277         if ((params == null) || !params.isZoomSupported()
278                 || (mZoomRenderer == null)) return;
279         mZoomMax = params.getMaxZoom();
280         mZoomRatios = params.getZoomRatios();
281         // Currently we use immediate zoom for fast zooming to get better UX and
282         // there is no plan to take advantage of the smooth zoom.
283         if (mZoomRenderer != null) {
284             mZoomRenderer.setZoomMax(mZoomMax);
285             mZoomRenderer.setZoom(params.getZoom());
286             mZoomRenderer.setZoomValue(mZoomRatios.get(params.getZoom()));
287             mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener());
288         }
289     }
290
291     public void enableGestures(boolean enable) {
292         if (mGestures != null) {
293             mGestures.setEnabled(enable);
294         }
295     }
296
297     public void showGpsOnScreenIndicator(boolean hasSignal) { }
298
299     public void hideGpsOnScreenIndicator() { }
300
301     public void overrideSettings(final String ... keyvalues) {
302         mMenu.overrideSettings(keyvalues);
303     }
304
305     public void updateOnScreenIndicators(Camera.Parameters params,
306             ComboPreferences prefs) {
307         if (params == null) return;
308         updateSceneOnScreenIndicator(params.getSceneMode());
309         updateExposureOnScreenIndicator(params,
310                 CameraSettings.readExposure(prefs));
311         updateFlashOnScreenIndicator(params.getFlashMode());
312         updateHdrOnScreenIndicator(params.getSceneMode());
313     }
314
315     private void updateExposureOnScreenIndicator(Camera.Parameters params, int value) {
316         if (mExposureIndicator == null) {
317             return;
318         }
319         int id = 0;
320         float step = params.getExposureCompensationStep();
321         value = (int) Math.round(value * step);
322         switch(value) {
323         case -3:
324             id = R.drawable.ic_indicator_ev_n3;
325             break;
326         case -2:
327             id = R.drawable.ic_indicator_ev_n2;
328             break;
329         case -1:
330             id = R.drawable.ic_indicator_ev_n1;
331             break;
332         case 0:
333             id = R.drawable.ic_indicator_ev_0;
334             break;
335         case 1:
336             id = R.drawable.ic_indicator_ev_p1;
337             break;
338         case 2:
339             id = R.drawable.ic_indicator_ev_p2;
340             break;
341         case 3:
342             id = R.drawable.ic_indicator_ev_p3;
343             break;
344         }
345         mExposureIndicator.setImageResource(id);
346     }
347
348     private void updateFlashOnScreenIndicator(String value) {
349         if (mFlashIndicator == null) {
350             return;
351         }
352         if (value == null || Parameters.FLASH_MODE_OFF.equals(value)) {
353             mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_off);
354         } else {
355             if (Parameters.FLASH_MODE_AUTO.equals(value)) {
356                 mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_auto);
357             } else if (Parameters.FLASH_MODE_ON.equals(value)) {
358                 mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_on);
359             } else {
360                 mFlashIndicator.setImageResource(R.drawable.ic_indicator_flash_off);
361             }
362         }
363     }
364
365     private void updateSceneOnScreenIndicator(String value) {
366         if (mSceneIndicator == null) {
367             return;
368         }
369         if ((value == null) || Parameters.SCENE_MODE_AUTO.equals(value)
370                 || Parameters.SCENE_MODE_HDR.equals(value)) {
371             mSceneIndicator.setImageResource(R.drawable.ic_indicator_sce_off);
372         } else {
373             mSceneIndicator.setImageResource(R.drawable.ic_indicator_sce_on);
374         }
375     }
376
377     private void updateHdrOnScreenIndicator(String value) {
378         if (mHdrIndicator == null) {
379             return;
380         }
381         if ((value != null) && Parameters.SCENE_MODE_HDR.equals(value)) {
382             mHdrIndicator.setImageResource(R.drawable.ic_indicator_hdr_on);
383         } else {
384             mHdrIndicator.setImageResource(R.drawable.ic_indicator_hdr_off);
385         }
386     }
387
388     public void setCameraState(int state) {
389     }
390
391     public boolean dispatchTouchEvent(MotionEvent m) {
392         if (mPopup != null) {
393             return mActivity.superDispatchTouchEvent(m);
394         } else if (mGestures != null && mRenderOverlay != null) {
395             return mGestures.dispatchTouch(m);
396         }
397         return false;
398     }
399
400     public boolean onBackPressed() {
401         if (mPieRenderer != null && mPieRenderer.showsItems()) {
402             mPieRenderer.hide();
403             return true;
404         }
405         // In image capture mode, back button should:
406         // 1) if there is any popup, dismiss them, 2) otherwise, get out of
407         // image capture
408         if (mController.isImageCaptureIntent()) {
409             if (!removeTopLevelPopup()) {
410                 // no popup to dismiss, cancel image capture
411                 mController.onCaptureCancelled();
412             }
413             return true;
414         } else if (!mController.isCameraIdle()) {
415             // ignore backs while we're taking a picture
416             return true;
417         } else {
418             return removeTopLevelPopup();
419         }
420     }
421
422     public void onFullScreenChanged(boolean full) {
423         if (mFaceView != null) {
424             mFaceView.setBlockDraw(!full);
425         }
426         if (mPopup != null) {
427             dismissPopup(false, full);
428         }
429         if (mGestures != null) {
430             mGestures.setEnabled(full);
431         }
432         if (mRenderOverlay != null) {
433             // this can not happen in capture mode
434             mRenderOverlay.setVisibility(full ? View.VISIBLE : View.GONE);
435         }
436         if (mPieRenderer != null) {
437             mPieRenderer.setBlockFocus(!full);
438         }
439         setShowMenu(full);
440         if (mBlocker != null) {
441             mBlocker.setVisibility(full ? View.VISIBLE : View.GONE);
442         }
443         if (!full && mCountDownView != null) mCountDownView.cancelCountDown();
444     }
445
446     public boolean removeTopLevelPopup() {
447         // Remove the top level popup or dialog box and return true if there's any
448         if (mPopup != null) {
449             dismissPopup(true);
450             return true;
451         }
452         return false;
453     }
454
455     public void showPopup(AbstractSettingPopup popup) {
456         mActivity.hideUI();
457         mBlocker.setVisibility(View.INVISIBLE);
458         setShowMenu(false);
459         mPopup = popup;
460         mPopup.setVisibility(View.VISIBLE);
461         FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
462                 LayoutParams.WRAP_CONTENT);
463         lp.gravity = Gravity.CENTER;
464         ((FrameLayout) mRootView).addView(mPopup, lp);
465     }
466
467     public void dismissPopup(boolean topPopupOnly) {
468         dismissPopup(topPopupOnly, true);
469     }
470
471     private void dismissPopup(boolean topOnly, boolean fullScreen) {
472         if (fullScreen) {
473             mActivity.showUI();
474             mBlocker.setVisibility(View.VISIBLE);
475         }
476         setShowMenu(fullScreen);
477         if (mPopup != null) {
478             ((FrameLayout) mRootView).removeView(mPopup);
479             mPopup = null;
480         }
481         mMenu.popupDismissed(topOnly);
482     }
483
484     public void onShowSwitcherPopup() {
485         if (mPieRenderer != null && mPieRenderer.showsItems()) {
486             mPieRenderer.hide();
487         }
488     }
489
490     private void setShowMenu(boolean show) {
491         if (mOnScreenIndicators != null) {
492             mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE);
493         }
494         if (mMenuButton != null) {
495             mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE);
496         }
497     }
498
499     public boolean collapseCameraControls() {
500         // Remove all the popups/dialog boxes
501         boolean ret = false;
502         if (mPopup != null) {
503             dismissPopup(false);
504             ret = true;
505         }
506         return ret;
507     }
508
509     protected void showPostCaptureAlert() {
510         mOnScreenIndicators.setVisibility(View.GONE);
511         mMenuButton.setVisibility(View.GONE);
512         Util.fadeIn(mReviewDoneButton);
513         mShutterButton.setVisibility(View.INVISIBLE);
514         Util.fadeIn(mReviewRetakeButton);
515     }
516
517     protected void hidePostCaptureAlert() {
518         mOnScreenIndicators.setVisibility(View.VISIBLE);
519         mMenuButton.setVisibility(View.VISIBLE);
520         Util.fadeOut(mReviewDoneButton);
521         mShutterButton.setVisibility(View.VISIBLE);
522         Util.fadeOut(mReviewRetakeButton);
523     }
524
525     public void setDisplayOrientation(int orientation) {
526         if (mFaceView != null) {
527             mFaceView.setDisplayOrientation(orientation);
528         }
529     }
530
531     // shutter button handling
532
533     public boolean isShutterPressed() {
534         return mShutterButton.isPressed();
535     }
536
537     // focus handling
538
539
540     private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
541         @Override
542         public void onZoomValueChanged(int index) {
543             int newZoom = mController.onZoomChanged(index);
544             if (mZoomRenderer != null) {
545                 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom));
546             }
547         }
548
549         @Override
550         public void onZoomStart() {
551             if (mPieRenderer != null) {
552                 mPieRenderer.setBlockFocus(true);
553             }
554         }
555
556         @Override
557         public void onZoomEnd() {
558             if (mPieRenderer != null) {
559                 mPieRenderer.setBlockFocus(false);
560             }
561         }
562     }
563
564     @Override
565     public void onPieOpened(int centerX, int centerY) {
566         mActivity.cancelActivityTouchHandling();
567         mActivity.setSwipingEnabled(false);
568         if (mFaceView != null) {
569             mFaceView.setBlockDraw(true);
570         }
571     }
572
573     @Override
574     public void onPieClosed() {
575         mActivity.setSwipingEnabled(true);
576         if (mFaceView != null) {
577             mFaceView.setBlockDraw(false);
578         }
579     }
580
581     // Surface Listener
582
583     @Override
584     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
585         Log.v(TAG, "surfaceChanged:" + holder + " width=" + width + ". height="
586                 + height);
587     }
588
589     @Override
590     public void surfaceCreated(SurfaceHolder holder) {
591         Log.v(TAG, "surfaceCreated: " + holder);
592         mSurfaceHolder = holder;
593         mController.onSurfaceCreated(holder);
594     }
595
596     @Override
597     public void surfaceDestroyed(SurfaceHolder holder) {
598         Log.v(TAG, "surfaceDestroyed: " + holder);
599         mSurfaceHolder = null;
600         mController.stopPreview();
601     }
602
603     public Object getSurfaceTexture() {
604         return mSurfaceTexture;
605     }
606
607     public void setSurfaceTexture(Object st) {
608         mSurfaceTexture = st;
609     }
610
611     public SurfaceHolder getSurfaceHolder() {
612         return mSurfaceHolder;
613     }
614
615     public boolean isCountingDown() {
616         return mCountDownView.isCountingDown();
617     }
618
619     public void cancelCountDown() {
620         mCountDownView.cancelCountDown();
621     }
622
623     public void startCountDown(int sec, boolean playSound) {
624         mCountDownView.startCountDown(sec, playSound);
625     }
626
627     public void showPreferencesToast() {
628         if (mNotSelectableToast == null) {
629             String str = mActivity.getResources().getString(R.string.not_selectable_in_scene_mode);
630             mNotSelectableToast = Toast.makeText(mActivity, str, Toast.LENGTH_SHORT);
631         }
632         mNotSelectableToast.show();
633     }
634
635     public void onPause() {
636         mCountDownView.cancelCountDown();
637         // Close the camera now because other activities may need to use it.
638         mSurfaceTexture = null;
639
640         // Clear UI.
641         collapseCameraControls();
642         if (mFaceView != null) mFaceView.clear();
643
644
645         mRootView.removeOnLayoutChangeListener(mLayoutListener);
646         mPreviewWidth = 0;
647         mPreviewHeight = 0;
648     }
649
650     public void enableShutter(boolean enabled) {
651         if (mShutterButton != null) {
652             mShutterButton.setEnabled(enabled);
653         }
654     }
655
656     public void pressShutterButton() {
657         if (mShutterButton.isInTouchMode()) {
658             mShutterButton.requestFocusFromTouch();
659         } else {
660             mShutterButton.requestFocus();
661         }
662         mShutterButton.setPressed(true);
663     }
664
665     // forward from preview gestures to controller
666     @Override
667     public void onSingleTapUp(View view, int x, int y) {
668         mController.onSingleTapUp(view, x, y);
669     }
670
671     // focus UI implementation
672
673     private FocusIndicator getFocusIndicator() {
674         return (mFaceView != null && mFaceView.faceExists()) ? mFaceView : mPieRenderer;
675     }
676
677     @Override
678     public boolean hasFaces() {
679         return (mFaceView != null && mFaceView.faceExists());
680     }
681
682     public void clearFaces() {
683         if (mFaceView != null) mFaceView.clear();
684     }
685
686     @Override
687     public void clearFocus() {
688         FocusIndicator indicator = getFocusIndicator();
689         if (indicator != null) indicator.clear();
690     }
691
692     @Override
693     public void setFocusPosition(int x, int y) {
694         mPieRenderer.setFocus(x, y);
695     }
696
697     @Override
698     public void onFocusStarted() {
699         getFocusIndicator().showStart();
700     }
701
702     @Override
703     public void onFocusSucceeded(boolean timeout) {
704         getFocusIndicator().showSuccess(timeout);
705     }
706
707     @Override
708     public void onFocusFailed(boolean timeout) {
709         getFocusIndicator().showFail(timeout);
710     }
711
712     @Override
713     public void pauseFaceDetection() {
714         if (mFaceView != null) mFaceView.pause();
715     }
716
717     @Override
718     public void resumeFaceDetection() {
719         if (mFaceView != null) mFaceView.resume();
720     }
721
722     public void onStartFaceDetection(int orientation, boolean mirror) {
723         mFaceView.clear();
724         mFaceView.setVisibility(View.VISIBLE);
725         mFaceView.setDisplayOrientation(orientation);
726         mFaceView.setMirror(mirror);
727         mFaceView.resume();
728     }
729
730     @Override
731     public void onFaceDetection(Face[] faces, android.hardware.Camera camera) {
732         mFaceView.setFaces(faces);
733     }
734
735     @Override
736     public void onSwipe(int direction) {
737         if (direction == PreviewGestures.DIR_UP) {
738             openMenu();
739         }
740     }
741
742 }