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