OSDN Git Service

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