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