PhotoModule.java revision 90ef46f0248437fbcb2c80c8a65239f4da32b039
1d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb/*
2d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb * Copyright (C) 2012 The Android Open Source Project
3d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb *
4d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb * Licensed under the Apache License, Version 2.0 (the "License");
5d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb * you may not use this file except in compliance with the License.
6d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb * You may obtain a copy of the License at
7d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb *
8d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb *      http://www.apache.org/licenses/LICENSE-2.0
9d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb *
10d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb * Unless required by applicable law or agreed to in writing, software
11d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb * distributed under the License is distributed on an "AS IS" BASIS,
12d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb * See the License for the specific language governing permissions and
14d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb * limitations under the License.
15d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb */
16d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
17d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbpackage com.android.camera;
18d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
19d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.annotation.TargetApi;
20d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.app.Activity;
21d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.content.BroadcastReceiver;
22d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.content.ContentProviderClient;
23d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.content.ContentResolver;
24d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.content.Context;
25d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.content.Intent;
26d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.content.IntentFilter;
27d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.content.SharedPreferences.Editor;
28d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.content.res.Configuration;
29d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.graphics.Bitmap;
30d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.graphics.SurfaceTexture;
31d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.hardware.Camera.CameraInfo;
32d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.hardware.Camera.Face;
33d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.hardware.Camera.FaceDetectionListener;
34d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.hardware.Camera.Parameters;
35d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.hardware.Camera.PictureCallback;
36d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.hardware.Camera.Size;
37d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.location.Location;
38d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.media.CameraProfile;
39d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.net.Uri;
40d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.os.Bundle;
41d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.os.ConditionVariable;
42d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.os.Handler;
43d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.os.Looper;
44d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.os.Message;
45d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.os.MessageQueue;
46d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.os.SystemClock;
47d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.provider.MediaStore;
48d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.util.Log;
49d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.view.KeyEvent;
50d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.view.LayoutInflater;
51d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.view.MotionEvent;
52d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.view.OrientationEventListener;
53d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.view.SurfaceHolder;
54d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.view.View;
5590ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolbimport android.view.View.OnClickListener;
56d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.view.ViewGroup;
57d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.view.WindowManager;
58d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.widget.ImageView;
59d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.widget.TextView;
60d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport android.widget.Toast;
61d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
62d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport com.android.camera.CameraManager.CameraProxy;
63d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport com.android.camera.ui.FaceView;
64b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolbimport com.android.camera.ui.FocusRenderer;
65d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport com.android.camera.ui.PopupManager;
66d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport com.android.camera.ui.PreviewSurfaceView;
67b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolbimport com.android.camera.ui.RenderOverlay;
68d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport com.android.camera.ui.Rotatable;
69d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport com.android.camera.ui.RotateImageView;
70d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport com.android.camera.ui.RotateLayout;
71d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport com.android.camera.ui.RotateTextToast;
72d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport com.android.camera.ui.TwoStateImageView;
73d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport com.android.camera.ui.ZoomControl;
74d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport com.android.gallery3d.common.ApiHelper;
75d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
76d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport java.io.File;
77d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport java.io.FileNotFoundException;
78d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport java.io.FileOutputStream;
79d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport java.io.IOException;
80d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport java.io.OutputStream;
81d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport java.util.ArrayList;
82d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport java.util.Collections;
83d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport java.util.Formatter;
84d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbimport java.util.List;
85d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
86d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolbpublic class PhotoModule
87d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    implements CameraModule,
88b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb    FocusOverlayManager.Listener,
89d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    CameraPreference.OnPreferenceChangedListener,
90d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    LocationManager.Listener,
91d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    PreviewFrameLayout.OnSizeChangedListener,
92d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    ShutterButton.OnShutterButtonListener,
93d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    SurfaceHolder.Callback {
94d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
95d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final String TAG = "CAM_PhotoModule";
96d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
97d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // We number the request code from 1000 to avoid collision with Gallery.
98d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int REQUEST_CROP = 1000;
99d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
100d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int SETUP_PREVIEW = 1;
101d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int FIRST_TIME_INIT = 2;
102d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int CLEAR_SCREEN_DELAY = 3;
103d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int SET_CAMERA_PARAMETERS_WHEN_IDLE = 4;
104d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int CHECK_DISPLAY_ROTATION = 5;
105d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int SHOW_TAP_TO_FOCUS_TOAST = 6;
106d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int UPDATE_THUMBNAIL = 7;
107d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int SWITCH_CAMERA = 8;
108d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int SWITCH_CAMERA_START_ANIMATION = 9;
109d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int CAMERA_OPEN_DONE = 10;
110d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int START_PREVIEW_DONE = 11;
111d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int OPEN_CAMERA_FAIL = 12;
112d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int CAMERA_DISABLED = 13;
113d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
114d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // The subset of parameters we need to update in setCameraParameters().
115d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int UPDATE_PARAM_INITIALIZE = 1;
116d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int UPDATE_PARAM_ZOOM = 2;
117d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int UPDATE_PARAM_PREFERENCE = 4;
118d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int UPDATE_PARAM_ALL = -1;
119d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
120d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // copied from Camera hierarchy
121d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private CameraActivity mActivity;
122d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private View mRootView;
123d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private CameraProxy mCameraDevice;
124d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int mCameraId;
125d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private Parameters mParameters;
126d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mPaused;
127d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
128d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // these are only used by Camera
129d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
130d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // The activity is going to switch to the specified camera id. This is
131d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // needed because texture copy is done in GL thread. -1 means camera is not
132d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // switching.
133d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    protected int mPendingSwitchCameraId = -1;
134d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mOpenCameraFail;
135d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mCameraDisabled;
136d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
137d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // When setCameraParametersWhenIdle() is called, we accumulate the subsets
138d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // needed to be updated in mUpdateSet.
139d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int mUpdateSet;
140d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
141d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int SCREEN_DELAY = 2 * 60 * 1000;
142d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
143d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int mZoomValue;  // The current zoom value.
144d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int mZoomMax;
145d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
146d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private Parameters mInitialParams;
147d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mFocusAreaSupported;
148d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mMeteringAreaSupported;
149d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mAeLockSupported;
150d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mAwbLockSupported;
151d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mContinousFocusSupported;
152d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
153d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private MyOrientationEventListener mOrientationListener;
154d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // The degrees of the device rotated clockwise from its natural orientation.
155d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
156d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // The orientation compensation for icons and thumbnails. Ex: if the value
157d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // is 90, the UI components should be rotated 90 degrees counter-clockwise.
158d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int mOrientationCompensation = 0;
159d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ComboPreferences mPreferences;
160d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
161d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final String sTempCropFilename = "crop-temp";
162d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
163d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ContentProviderClient mMediaProviderClient;
164d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ShutterButton mShutterButton;
165d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mFaceDetectionStarted = false;
166d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
167d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private PreviewFrameLayout mPreviewFrameLayout;
168d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private Object mSurfaceTexture;
169d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
170d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // for API level 10
171d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private PreviewSurfaceView mPreviewSurfaceView;
172d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private volatile SurfaceHolder mCameraSurfaceHolder;
173d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
174d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private RotateDialogController mRotateDialog;
175d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ModePicker mModePicker;
176d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private FaceView mFaceView;
177b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb    private RenderOverlay mRenderOverlay;
178d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private Rotatable mReviewCancelButton;
179d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private Rotatable mReviewDoneButton;
18090ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb//    private View mReviewRetakeButton;
181d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
182d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
183d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private String mCropValue;
184d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private Uri mSaveUri;
185d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
186d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // Small indicators which show the camera settings in the viewfinder.
187d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private TextView mExposureIndicator;
188d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ImageView mGpsIndicator;
189d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ImageView mFlashIndicator;
190d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ImageView mSceneIndicator;
191d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ImageView mWhiteBalanceIndicator;
192d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ImageView mFocusIndicator;
193d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // A view group that contains all the small indicators.
194d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private Rotatable mOnScreenIndicators;
195d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
196d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // We use a thread in ImageSaver to do the work of saving images and
197d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // generating thumbnails. This reduces the shot-to-shot time.
198d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ImageSaver mImageSaver;
199d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // Similarly, we use a thread to generate the name of the picture and insert
200d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // it into MediaStore while picture taking is still in progress.
201d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ImageNamer mImageNamer;
202d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
203d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private SoundClips.Player mSoundPlayer;
204d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
205d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private Runnable mDoSnapRunnable = new Runnable() {
206d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
207d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void run() {
208d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            onShutterButtonClick();
209d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
210d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    };
211d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
212d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final StringBuilder mBuilder = new StringBuilder();
213d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final Formatter mFormatter = new Formatter(mBuilder);
214d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final Object[] mFormatterArgs = new Object[1];
215d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
216d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    /**
217d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb     * An unpublished intent flag requesting to return as soon as capturing
218d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb     * is completed.
219d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb     *
220d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb     * TODO: consider publishing by moving into MediaStore.
221d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb     */
222d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final String EXTRA_QUICK_CAPTURE =
223d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            "android.intent.extra.quickCapture";
224d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
225d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // The display rotation in degrees. This is only valid when mCameraState is
226d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // not PREVIEW_STOPPED.
227d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int mDisplayRotation;
228d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // The value for android.hardware.Camera.setDisplayOrientation.
229d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int mCameraDisplayOrientation;
230d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // The value for UI components like indicators.
231d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int mDisplayOrientation;
232d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // The value for android.hardware.Camera.Parameters.setRotation.
233d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int mJpegRotation;
234d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mFirstTimeInitialized;
235d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mIsImageCaptureIntent;
236d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
237d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int PREVIEW_STOPPED = 0;
238d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int IDLE = 1;  // preview is active
239d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // Focus is in progress. The exact focus state is in Focus.java.
240d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int FOCUSING = 2;
241d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int SNAPSHOT_IN_PROGRESS = 3;
242d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // Switching between cameras.
243d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static final int SWITCHING_CAMERA = 4;
244d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int mCameraState = PREVIEW_STOPPED;
245d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mSnapshotOnIdle = false;
246d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
247d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private ContentResolver mContentResolver;
248d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mDidRegister = false;
249d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
250d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private LocationManager mLocationManager;
251d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
252d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final ShutterCallback mShutterCallback = new ShutterCallback();
253d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final PostViewPictureCallback mPostViewPictureCallback =
254d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            new PostViewPictureCallback();
255d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final RawPictureCallback mRawPictureCallback =
256d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            new RawPictureCallback();
257d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final AutoFocusCallback mAutoFocusCallback =
258d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            new AutoFocusCallback();
259d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final Object mAutoFocusMoveCallback =
260d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK
261d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            ? new AutoFocusMoveCallback()
262d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            : null;
263d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
264d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
265d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
266d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private long mFocusStartTime;
267d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private long mShutterCallbackTime;
268d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private long mPostViewPictureCallbackTime;
269d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private long mRawPictureCallbackTime;
270d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private long mJpegPictureCallbackTime;
271d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private long mOnResumeTime;
272d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private byte[] mJpegImageData;
273d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
274d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // These latency time are for the CameraLatency test.
275d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public long mAutoFocusTime;
276d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public long mShutterLag;
277d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public long mShutterToPictureDisplayedTime;
278d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public long mPictureDisplayedToJpegCallbackTime;
279d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public long mJpegCallbackFinishTime;
280d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public long mCaptureStartTime;
281d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
282d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // This handles everything about focus.
283b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb    private FocusOverlayManager mFocusManager;
284b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb    private FocusRenderer mFocusRenderer;
285b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb
286d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private String mSceneMode;
287d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private Toast mNotSelectableToast;
288d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
289d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final Handler mHandler = new MainHandler();
290d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private PreferenceGroup mPreferenceGroup;
291d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
292d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean mQuickCapture;
293d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
294d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    CameraStartUpThread mCameraStartUpThread;
295d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    ConditionVariable mStartPreviewPrerequisiteReady = new ConditionVariable();
296d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
297d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    protected class CameraOpenThread extends Thread {
298d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
299d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void run() {
300d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            try {
301d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mCameraDevice = Util.openCamera(mActivity, mCameraId);
302d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mParameters = mCameraDevice.getParameters();
303d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } catch (CameraHardwareException e) {
304d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mOpenCameraFail = true;
305d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } catch (CameraDisabledException e) {
306d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mCameraDisabled = true;
307d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
308d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
309d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
310d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
311d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // The purpose is not to block the main thread in onCreate and onResume.
312d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private class CameraStartUpThread extends Thread {
313d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private volatile boolean mCancelled;
314d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
315d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void cancel() {
316d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCancelled = true;
317d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
318d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
319d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
320d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void run() {
321d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            try {
322d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // We need to check whether the activity is paused before long
323d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // operations to ensure that onPause() can be done ASAP.
324d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (mCancelled) return;
325d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mCameraDevice = Util.openCamera(mActivity, mCameraId);
326d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mParameters = mCameraDevice.getParameters();
327d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // Wait until all the initialization needed by startPreview are
328d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // done.
329d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mStartPreviewPrerequisiteReady.block();
330d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
331d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                initializeCapabilities();
332d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (mFocusManager == null) initializeFocusManager();
333d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (mCancelled) return;
334d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                setCameraParameters(UPDATE_PARAM_ALL);
335d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mHandler.sendEmptyMessage(CAMERA_OPEN_DONE);
336d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (mCancelled) return;
337d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                startPreview();
338d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mHandler.sendEmptyMessage(START_PREVIEW_DONE);
339d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mOnResumeTime = SystemClock.uptimeMillis();
340d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mHandler.sendEmptyMessage(CHECK_DISPLAY_ROTATION);
341d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } catch (CameraHardwareException e) {
342d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL);
343d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } catch (CameraDisabledException e) {
344d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mHandler.sendEmptyMessage(CAMERA_DISABLED);
345d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
346d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
347d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
348d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
349d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    /**
350d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb     * This Handler is used to post message back onto the main thread of the
351d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb     * application
352d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb     */
353d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private class MainHandler extends Handler {
354d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
355d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void handleMessage(Message msg) {
356d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            switch (msg.what) {
357d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case SETUP_PREVIEW: {
358d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    setupPreview();
359d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
360d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
361d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
362d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case CLEAR_SCREEN_DELAY: {
363d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mActivity.getWindow().clearFlags(
364d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
365d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
366d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
367d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
368d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case FIRST_TIME_INIT: {
369d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    initializeFirstTime();
370d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
371d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
372d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
373d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case SET_CAMERA_PARAMETERS_WHEN_IDLE: {
374d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    setCameraParametersWhenIdle(0);
375d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
376d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
377d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
378d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case CHECK_DISPLAY_ROTATION: {
379d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // Set the display orientation if display rotation has changed.
380d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // Sometimes this happens when the device is held upside
381d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // down and camera app is opened. Rotation animation will
382d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // take some time and the rotation value we have got may be
383d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // wrong. Framework does not have a callback for this now.
384d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    if (Util.getDisplayRotation(mActivity) != mDisplayRotation) {
385d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        setDisplayOrientation();
386d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    }
387d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
388d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100);
389d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    }
390d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
391d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
392d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
393d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case SHOW_TAP_TO_FOCUS_TOAST: {
394d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    showTapToFocusToast();
395d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
396d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
397d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
398d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case UPDATE_THUMBNAIL: {
399d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mImageSaver.updateThumbnail();
400d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
401d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
402d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
403d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case SWITCH_CAMERA: {
404d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    switchCamera();
405d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
406d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
407d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
408d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case SWITCH_CAMERA_START_ANIMATION: {
409b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb                    ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera();
410d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
411d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
412d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
413d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case CAMERA_OPEN_DONE: {
414d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    initializeAfterCameraOpen();
415d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
416d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
417d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
418d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case START_PREVIEW_DONE: {
419d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mCameraStartUpThread = null;
420d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    setCameraState(IDLE);
421d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    if (!ApiHelper.HAS_SURFACE_TEXTURE) {
422d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        // This may happen if surfaceCreated has arrived.
423d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        mCameraDevice.setPreviewDisplayAsync(mCameraSurfaceHolder);
424d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    }
425d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    startFaceDetection();
426d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
427d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
428d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
429d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case OPEN_CAMERA_FAIL: {
430d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mCameraStartUpThread = null;
431d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mOpenCameraFail = true;
432d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    Util.showErrorAndFinish(mActivity,
433d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                            R.string.cannot_connect_camera);
434d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
435d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
436d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
437d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                case CAMERA_DISABLED: {
438d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mCameraStartUpThread = null;
439d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mCameraDisabled = true;
440d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    Util.showErrorAndFinish(mActivity,
441d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                            R.string.camera_disabled);
442d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    break;
443d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
444d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
445d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
446d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
447d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
448d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
449ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb    public void init(CameraActivity activity, View parent, boolean reuseNail) {
450d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mActivity = activity;
451d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mRootView = parent;
452d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPreferences = new ComboPreferences(mActivity);
453d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
454d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraId = getPreferredCameraId(mPreferences);
455d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
456d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mContentResolver = mActivity.getContentResolver();
457d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
458d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // To reduce startup time, open the camera and start the preview in
459d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // another thread.
460d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraStartUpThread = new CameraStartUpThread();
461d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraStartUpThread.start();
462d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
463d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mActivity.getLayoutInflater().inflate(R.layout.photo_module, (ViewGroup) mRootView);
464d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
465d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Surface texture is from camera screen nail and startPreview needs it.
466d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // This must be done before startPreview.
467d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mIsImageCaptureIntent = isImageCaptureIntent();
468ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb        if (reuseNail) {
469ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb            mActivity.reuseCameraScreenNail(!mIsImageCaptureIntent);
470ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb        } else {
471ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb            mActivity.createCameraScreenNail(!mIsImageCaptureIntent);
472ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb        }
473d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
474d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPreferences.setLocalId(mActivity, mCameraId);
475d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
476d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // we need to reset exposure for the preview
477d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        resetExposureCompensation();
478d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Starting the preview needs preferences, camera screen nail, and
479d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // focus area indicator.
480d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mStartPreviewPrerequisiteReady.open();
481d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
482d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initializeControlByIntent();
483d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mRotateDialog = new RotateDialogController(mActivity, R.layout.rotate_dialog);
484d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
485d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initializeMiscControls();
486d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mLocationManager = new LocationManager(mActivity, this);
487d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initOnScreenIndicator();
488d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Make sure all views are disabled before camera is open.
489b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb//        enableCameraControls(false);
490d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
491d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
492d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void initializeAfterCameraOpen() {
493b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb        mFocusRenderer = new FocusRenderer();
494b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb        mRenderOverlay.addRenderer(mFocusRenderer);
495b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb        mFocusManager.setFocusRenderer(mFocusRenderer);
496b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb        mRenderOverlay.requestLayout();
497b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb
498d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // These depend on camera parameters.
499d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setPreviewFrameLayoutAspectRatio();
500d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFocusManager.setPreviewSize(mPreviewFrameLayout.getWidth(),
501d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mPreviewFrameLayout.getHeight());
502b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb        loadCameraPreferences();
503d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initializeZoom();
504d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        updateOnScreenIndicators();
505d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        showTapToFocusToastIfNeeded();
506d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
507d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
508d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void resetExposureCompensation() {
509d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE,
510d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                CameraSettings.EXPOSURE_DEFAULT_VALUE);
511d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!CameraSettings.EXPOSURE_DEFAULT_VALUE.equals(value)) {
512d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Editor editor = mPreferences.edit();
513d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            editor.putString(CameraSettings.KEY_EXPOSURE, "0");
514d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            editor.apply();
515d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
516d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
517d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
518d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void keepMediaProviderInstance() {
519d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // We want to keep a reference to MediaProvider in camera's lifecycle.
520d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // TODO: Utilize mMediaProviderClient instance to replace
521d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // ContentResolver calls.
522d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mMediaProviderClient == null) {
523d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mMediaProviderClient = mContentResolver
524d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    .acquireContentProviderClient(MediaStore.AUTHORITY);
525d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
526d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
527d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
528d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // Snapshots can only be taken after this is called. It should be called
529d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // once only. We could have done these things in onCreate() but we want to
530d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // make preview screen appear as soon as possible.
531d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void initializeFirstTime() {
532d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFirstTimeInitialized) return;
533d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
534d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Create orientation listener. This should be done first because it
535d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // takes some time to get first orientation.
536d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mOrientationListener = new MyOrientationEventListener(mActivity);
537d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mOrientationListener.enable();
538d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
539d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Initialize location service.
540d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        boolean recordLocation = RecordLocationPreference.get(
541d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mPreferences, mContentResolver);
542d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mLocationManager.recordLocation(recordLocation);
543d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
544d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        keepMediaProviderInstance();
545d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
546d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Initialize shutter button.
547d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mShutterButton = mActivity.getShutterButton();
548566f11c903ceae2e53c645f8d630bb1331faf890Michael Kolb        mShutterButton.setImageResource(R.drawable.btn_new_shutter);
549d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mShutterButton.setOnShutterButtonListener(this);
550d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mShutterButton.setVisibility(View.VISIBLE);
551d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
552d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mImageSaver = new ImageSaver();
553d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mImageNamer = new ImageNamer();
554d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
555d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFirstTimeInitialized = true;
556d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        addIdleHandler();
557d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
558d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mActivity.updateStorageSpaceAndHint();
559d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
560d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
561d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void showTapToFocusToastIfNeeded() {
562d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Show the tap to focus toast if this is the first start.
563d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFocusAreaSupported &&
564d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) {
565d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Delay the toast for one second to wait for orientation.
566d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000);
567d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
568d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
569d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
570d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void addIdleHandler() {
571d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        MessageQueue queue = Looper.myQueue();
572d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        queue.addIdleHandler(new MessageQueue.IdleHandler() {
573d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            @Override
574d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            public boolean queueIdle() {
575d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                Storage.ensureOSXCompatible();
576d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                return false;
577d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
578d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        });
579d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
580d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
581d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // If the activity is paused and resumed, this method will be called in
582d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // onResume.
583d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void initializeSecondTime() {
584d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Start orientation listener as soon as possible because it takes
585d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // some time to get first orientation.
586d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mOrientationListener.enable();
587d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
588d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Start location update if needed.
589d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        boolean recordLocation = RecordLocationPreference.get(
590d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mPreferences, mContentResolver);
591d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mLocationManager.recordLocation(recordLocation);
592d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
593d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mImageSaver = new ImageSaver();
594d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mImageNamer = new ImageNamer();
595d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initializeZoom();
596d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        keepMediaProviderInstance();
597d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        hidePostCaptureAlert();
598d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
599d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!mIsImageCaptureIntent) {
600d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mModePicker != null) {
601d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mModePicker.setCurrentMode(ModePicker.MODE_CAMERA);
602d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
603d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
604d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
605d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
606d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private class ZoomChangeListener implements ZoomControl.OnZoomChangedListener {
607d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
608d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void onZoomValueChanged(int index) {
609d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Not useful to change zoom value when the activity is paused.
610d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mPaused) return;
611d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mZoomValue = index;
612d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
613d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Set zoom parameters asynchronously
614d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters.setZoom(mZoomValue);
615d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setParametersAsync(mParameters);
616d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
617d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
618d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
619d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void initializeZoom() {
620d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!mParameters.isZoomSupported()) return;
621d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mZoomMax = mParameters.getMaxZoom();
622d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
623d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
624d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
625d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
626d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void startFaceDetection() {
627d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!ApiHelper.HAS_FACE_DETECTION) return;
628d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFaceDetectionStarted) return;
629d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mParameters.getMaxNumDetectedFaces() > 0) {
630d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceDetectionStarted = true;
631d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceView.clear();
632d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceView.setVisibility(View.VISIBLE);
633d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceView.setDisplayOrientation(mDisplayOrientation);
634d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
635d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceView.setMirror(info.facing == CameraInfo.CAMERA_FACING_FRONT);
636d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceView.resume();
637d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusManager.setFaceView(mFaceView);
638d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setFaceDetectionListener(new FaceDetectionListener() {
639d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                @Override
640d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                public void onFaceDetection(Face[] faces, android.hardware.Camera camera) {
641d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mFaceView.setFaces(faces);
642d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
643d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            });
644d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.startFaceDetection();
645d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
646d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
647d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
648d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
649d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
650d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
651d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void stopFaceDetection() {
652d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!ApiHelper.HAS_FACE_DETECTION) return;
653d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!mFaceDetectionStarted) return;
654d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mParameters.getMaxNumDetectedFaces() > 0) {
655d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceDetectionStarted = false;
656d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setFaceDetectionListener(null);
657d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.stopFaceDetection();
658d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mFaceView != null) mFaceView.clear();
659d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
660d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
661d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
662d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
663d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public boolean dispatchTouchEvent(MotionEvent m) {
664d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mCameraState == SWITCHING_CAMERA) return true;
665d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        return false;
666d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
667d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
668d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
669d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
670d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void onReceive(Context context, Intent intent) {
671d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            String action = intent.getAction();
672d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (!mIsImageCaptureIntent && action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
673d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.getLastThumbnail();
674d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
675d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
676d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    };
677d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
678d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void initOnScreenIndicator() {
679d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mGpsIndicator = (ImageView) mRootView.findViewById(R.id.onscreen_gps_indicator);
680d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mExposureIndicator = (TextView) mRootView.findViewById(R.id.onscreen_exposure_indicator);
681d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFlashIndicator = (ImageView) mRootView.findViewById(R.id.onscreen_flash_indicator);
682d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mSceneIndicator = (ImageView) mRootView.findViewById(R.id.onscreen_scene_indicator);
683d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mWhiteBalanceIndicator =
684d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                (ImageView) mRootView.findViewById(R.id.onscreen_white_balance_indicator);
685d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFocusIndicator = (ImageView) mRootView.findViewById(R.id.onscreen_focus_indicator);
686d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
687d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
688d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
689d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void showGpsOnScreenIndicator(boolean hasSignal) {
690d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mGpsIndicator == null) {
691d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
692d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
693d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (hasSignal) {
694d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mGpsIndicator.setImageResource(R.drawable.ic_viewfinder_gps_on);
695d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
696d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mGpsIndicator.setImageResource(R.drawable.ic_viewfinder_gps_no_signal);
697d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
698d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mGpsIndicator.setVisibility(View.VISIBLE);
699d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
700d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
701d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
702d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void hideGpsOnScreenIndicator() {
703d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mGpsIndicator == null) {
704d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
705d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
706d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mGpsIndicator.setVisibility(View.GONE);
707d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
708d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
709d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void updateExposureOnScreenIndicator(int value) {
710d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mExposureIndicator == null) {
711d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
712d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
713d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (value == 0) {
714d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mExposureIndicator.setText("");
715d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mExposureIndicator.setVisibility(View.GONE);
716d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
717d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            float step = mParameters.getExposureCompensationStep();
718d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFormatterArgs[0] = value * step;
719d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mBuilder.delete(0, mBuilder.length());
720d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFormatter.format("%+1.1f", mFormatterArgs);
721d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            String exposure = mFormatter.toString();
722d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mExposureIndicator.setText(exposure);
723d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mExposureIndicator.setVisibility(View.VISIBLE);
724d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
725d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
726d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
727d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void updateFlashOnScreenIndicator(String value) {
728d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFlashIndicator == null) {
729d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
730d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
731d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (value == null || Parameters.FLASH_MODE_OFF.equals(value)) {
732d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFlashIndicator.setVisibility(View.GONE);
733d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
734d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFlashIndicator.setVisibility(View.VISIBLE);
735d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (Parameters.FLASH_MODE_AUTO.equals(value)) {
736d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mFlashIndicator.setImageResource(R.drawable.ic_indicators_landscape_flash_auto);
737d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else if (Parameters.FLASH_MODE_ON.equals(value)) {
738d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mFlashIndicator.setImageResource(R.drawable.ic_indicators_landscape_flash_on);
739d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else {
740d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // Should not happen.
741d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mFlashIndicator.setVisibility(View.GONE);
742d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
743d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
744d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
745d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
746d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void updateSceneOnScreenIndicator(String value) {
747d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mSceneIndicator == null) {
748d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
749d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
750d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        boolean isGone = (value == null) || (Parameters.SCENE_MODE_AUTO.equals(value));
751d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mSceneIndicator.setVisibility(isGone ? View.GONE : View.VISIBLE);
752d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
753d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
754d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void updateWhiteBalanceOnScreenIndicator(String value) {
755d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mWhiteBalanceIndicator == null) {
756d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
757d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
758d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (value == null || Parameters.WHITE_BALANCE_AUTO.equals(value)) {
759d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mWhiteBalanceIndicator.setVisibility(View.GONE);
760d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
761d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mWhiteBalanceIndicator.setVisibility(View.VISIBLE);
762d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (Parameters.WHITE_BALANCE_FLUORESCENT.equals(value)) {
763d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mWhiteBalanceIndicator.setImageResource(R.drawable.ic_indicators_fluorescent);
764d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else if (Parameters.WHITE_BALANCE_INCANDESCENT.equals(value)) {
765d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mWhiteBalanceIndicator.setImageResource(R.drawable.ic_indicators_incandescent);
766d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else if (Parameters.WHITE_BALANCE_DAYLIGHT.equals(value)) {
767d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mWhiteBalanceIndicator.setImageResource(R.drawable.ic_indicators_sunlight);
768d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else if (Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT.equals(value)) {
769d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mWhiteBalanceIndicator.setImageResource(R.drawable.ic_indicators_cloudy);
770d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else {
771d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // Should not happen.
772d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mWhiteBalanceIndicator.setVisibility(View.GONE);
773d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
774d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
775d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
776d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
777d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void updateFocusOnScreenIndicator(String value) {
778d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFocusIndicator == null) {
779d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
780d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
781d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Do not show the indicator if users cannot choose.
782d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mPreferenceGroup.findPreference(CameraSettings.KEY_FOCUS_MODE) == null) {
783d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusIndicator.setVisibility(View.GONE);
784d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
785d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusIndicator.setVisibility(View.VISIBLE);
786d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (Parameters.FOCUS_MODE_INFINITY.equals(value)) {
787d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mFocusIndicator.setImageResource(R.drawable.ic_indicators_landscape);
788d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else if (Parameters.FOCUS_MODE_MACRO.equals(value)) {
789d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mFocusIndicator.setImageResource(R.drawable.ic_indicators_macro);
790d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else {
791d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // Should not happen.
792d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mFocusIndicator.setVisibility(View.GONE);
793d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
794d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
795d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
796d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
797d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void updateOnScreenIndicators() {
798d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        updateSceneOnScreenIndicator(mParameters.getSceneMode());
799d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        updateExposureOnScreenIndicator(CameraSettings.readExposure(mPreferences));
800d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        updateFlashOnScreenIndicator(mParameters.getFlashMode());
801d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        updateWhiteBalanceOnScreenIndicator(mParameters.getWhiteBalance());
802d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        updateFocusOnScreenIndicator(mParameters.getFocusMode());
803d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
804d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
805d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final class ShutterCallback
806d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            implements android.hardware.Camera.ShutterCallback {
807d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
808d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void onShutter() {
809d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mShutterCallbackTime = System.currentTimeMillis();
810d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mShutterLag = mShutterCallbackTime - mCaptureStartTime;
811d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
812d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
813d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
814d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
815d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final class PostViewPictureCallback implements PictureCallback {
816d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
817d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void onPictureTaken(
818d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                byte [] data, android.hardware.Camera camera) {
819d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mPostViewPictureCallbackTime = System.currentTimeMillis();
820d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Log.v(TAG, "mShutterToPostViewCallbackTime = "
821d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    + (mPostViewPictureCallbackTime - mShutterCallbackTime)
822d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    + "ms");
823d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
824d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
825d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
826d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final class RawPictureCallback implements PictureCallback {
827d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
828d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void onPictureTaken(
829d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                byte [] rawData, android.hardware.Camera camera) {
830d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mRawPictureCallbackTime = System.currentTimeMillis();
831d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Log.v(TAG, "mShutterToRawCallbackTime = "
832d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
833d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
834d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
835d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
836d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final class JpegPictureCallback implements PictureCallback {
837d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Location mLocation;
838d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
839d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public JpegPictureCallback(Location loc) {
840d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mLocation = loc;
841d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
842d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
843d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
844d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void onPictureTaken(
845d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                final byte [] jpegData, final android.hardware.Camera camera) {
846d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mPaused) {
847d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                return;
848d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
849d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
850d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mJpegPictureCallbackTime = System.currentTimeMillis();
851d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // If postview callback has arrived, the captured image is displayed
852d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // in postview callback. If not, the captured image is displayed in
853d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // raw picture callback.
854d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mPostViewPictureCallbackTime != 0) {
855d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mShutterToPictureDisplayedTime =
856d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        mPostViewPictureCallbackTime - mShutterCallbackTime;
857d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mPictureDisplayedToJpegCallbackTime =
858d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
859d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else {
860d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mShutterToPictureDisplayedTime =
861d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        mRawPictureCallbackTime - mShutterCallbackTime;
862d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mPictureDisplayedToJpegCallbackTime =
863d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        mJpegPictureCallbackTime - mRawPictureCallbackTime;
864d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
865d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = "
866d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    + mPictureDisplayedToJpegCallbackTime + "ms");
867d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
868d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden.
869d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (!mIsImageCaptureIntent) {
870d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (ApiHelper.CAN_START_PREVIEW_IN_JPEG_CALLBACK) {
871d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    setupPreview();
872d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                } else {
873d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // Camera HAL of some devices have a bug. Starting preview
874d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // immediately after taking a picture will fail. Wait some
875d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // time before starting the preview.
876d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mHandler.sendEmptyMessageDelayed(SETUP_PREVIEW, 300);
877d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
878d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
879d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
880d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (!mIsImageCaptureIntent) {
881d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // Calculate the width and the height of the jpeg.
882d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                Size s = mParameters.getPictureSize();
883d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                int orientation = Exif.getOrientation(jpegData);
884d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                int width, height;
885d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if ((mJpegRotation + orientation) % 180 == 0) {
886d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    width = s.width;
887d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    height = s.height;
888d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                } else {
889d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    width = s.height;
890d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    height = s.width;
891d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
892d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                Uri uri = mImageNamer.getUri();
893d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.addSecureAlbumItemIfNeeded(false, uri);
894d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                String title = mImageNamer.getTitle();
895d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mImageSaver.addImage(jpegData, uri, title, mLocation,
896d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        width, height, mActivity.mThumbnailViewWidth, orientation);
897d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else {
898d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mJpegImageData = jpegData;
899d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (!mQuickCapture) {
900d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    showPostCaptureAlert();
901d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                } else {
902d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    doAttach();
903d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
904d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
905d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
906d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Check this in advance of each shot so we don't add to shutter
907d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // latency. It's true that someone else could write to the SD card in
908d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // the mean time and fill it, but that could have happened between the
909d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // shutter press and saving the JPEG too.
910d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mActivity.updateStorageSpaceAndHint();
911d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
912d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            long now = System.currentTimeMillis();
913d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
914d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Log.v(TAG, "mJpegCallbackFinishTime = "
915d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    + mJpegCallbackFinishTime + "ms");
916d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mJpegPictureCallbackTime = 0;
917d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
918d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
919d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
920d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final class AutoFocusCallback
921d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            implements android.hardware.Camera.AutoFocusCallback {
922d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
923d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void onAutoFocus(
924d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                boolean focused, android.hardware.Camera camera) {
925d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mPaused) return;
926d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
927d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
928d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
929d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            setCameraState(IDLE);
930d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusManager.onAutoFocus(focused);
931d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
932d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
933d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
934d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
935d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private final class AutoFocusMoveCallback
936d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            implements android.hardware.Camera.AutoFocusMoveCallback {
937d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
938d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void onAutoFocusMoving(
939d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            boolean moving, android.hardware.Camera camera) {
940d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mFocusManager.onAutoFocusMoving(moving);
941d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
942d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
943d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
944d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // Each SaveRequest remembers the data needed to save an image.
945d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static class SaveRequest {
946d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        byte[] data;
947d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Uri uri;
948d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        String title;
949d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Location loc;
950d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        int width, height;
951d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        int thumbnailWidth;
952d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        int orientation;
953d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
954d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
955d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // We use a queue to store the SaveRequests that have not been completed
956d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // yet. The main thread puts the request into the queue. The saver thread
957d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // gets it from the queue, does the work, and removes it from the queue.
958d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    //
959d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // The main thread needs to wait for the saver thread to finish all the work
960d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // in the queue, when the activity's onPause() is called, we need to finish
961d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // all the work, so other programs (like Gallery) can see all the images.
962d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    //
963d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // If the queue becomes too long, adding a new request will block the main
964d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // thread until the queue length drops below the threshold (QUEUE_LIMIT).
965d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // If we don't do this, we may face several problems: (1) We may OOM
966d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // because we are holding all the jpeg data in memory. (2) We may ANR
967d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // when we need to wait for saver thread finishing all the work (in
968d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // onPause() or gotoGallery()) because the time to finishing a long queue
969d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // of work may be too long.
970d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private class ImageSaver extends Thread {
971d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private static final int QUEUE_LIMIT = 3;
972d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
973d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private ArrayList<SaveRequest> mQueue;
974d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private Thumbnail mPendingThumbnail;
975d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private Object mUpdateThumbnailLock = new Object();
976d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private boolean mStop;
977d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
978d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in main thread
979d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public ImageSaver() {
980d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mQueue = new ArrayList<SaveRequest>();
981d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            start();
982d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
983d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
984d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in main thread
985d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void addImage(final byte[] data, Uri uri, String title,
986d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                Location loc, int width, int height, int thumbnailWidth,
987d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                int orientation) {
988d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            SaveRequest r = new SaveRequest();
989d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            r.data = data;
990d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            r.uri = uri;
991d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            r.title = title;
992d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            r.loc = (loc == null) ? null : new Location(loc);  // make a copy
993d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            r.width = width;
994d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            r.height = height;
995d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            r.thumbnailWidth = thumbnailWidth;
996d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            r.orientation = orientation;
997d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            synchronized (this) {
998d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                while (mQueue.size() >= QUEUE_LIMIT) {
999d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    try {
1000d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        wait();
1001d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    } catch (InterruptedException ex) {
1002d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        // ignore.
1003d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    }
1004d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1005d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mQueue.add(r);
1006d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                notifyAll();  // Tell saver thread there is new work to do.
1007d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1008d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1009d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1010d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in saver thread
1011d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
1012d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void run() {
1013d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            while (true) {
1014d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                SaveRequest r;
1015d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                synchronized (this) {
1016d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    if (mQueue.isEmpty()) {
1017d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        notifyAll();  // notify main thread in waitDone
1018d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1019d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        // Note that we can only stop after we saved all images
1020d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        // in the queue.
1021d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        if (mStop) break;
1022d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1023d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        try {
1024d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                            wait();
1025d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        } catch (InterruptedException ex) {
1026d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                            // ignore.
1027d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        }
1028d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        continue;
1029d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    }
1030d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    r = mQueue.get(0);
1031d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1032d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                storeImage(r.data, r.uri, r.title, r.loc, r.width, r.height,
1033d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        r.thumbnailWidth, r.orientation);
1034d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                synchronized (this) {
1035d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mQueue.remove(0);
1036d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    notifyAll();  // the main thread may wait in addImage
1037d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1038d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1039d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1040d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1041d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in main thread
1042d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void waitDone() {
1043d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            synchronized (this) {
1044d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                while (!mQueue.isEmpty()) {
1045d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    try {
1046d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        wait();
1047d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    } catch (InterruptedException ex) {
1048d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        // ignore.
1049d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    }
1050d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1051d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1052d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            updateThumbnail();
1053d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1054d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1055d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in main thread
1056d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void finish() {
1057d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            waitDone();
1058d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            synchronized (this) {
1059d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mStop = true;
1060d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                notifyAll();
1061d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1062d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            try {
1063d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                join();
1064d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } catch (InterruptedException ex) {
1065d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // ignore.
1066d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1067d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1068d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1069d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in main thread (because we need to update mThumbnailView in the
1070d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // main thread)
1071d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void updateThumbnail() {
1072d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Thumbnail t;
1073d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            synchronized (mUpdateThumbnailLock) {
1074d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mHandler.removeMessages(UPDATE_THUMBNAIL);
1075d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                t = mPendingThumbnail;
1076d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mPendingThumbnail = null;
1077d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1078d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1079d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (t != null) {
1080d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.mThumbnail = t;
1081d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (mActivity.mThumbnailView != null) {
1082d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mActivity.mThumbnailView.setBitmap(mActivity.mThumbnail.getBitmap());
1083d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1084d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1085d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1086d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1087d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in saver thread
1088d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private void storeImage(final byte[] data, Uri uri, String title,
1089d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                Location loc, int width, int height, int thumbnailWidth,
1090d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                int orientation) {
1091d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            boolean ok = Storage.updateImage(mContentResolver, uri, title, loc,
1092d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    orientation, data, width, height);
1093d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (ok) {
1094d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                boolean needThumbnail;
1095d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                synchronized (this) {
1096d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // If the number of requests in the queue (include the
1097d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // current one) is greater than 1, we don't need to generate
1098d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // thumbnail for this image. Because we'll soon replace it
1099d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // with the thumbnail for some image later in the queue.
1100d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    needThumbnail = (mQueue.size() <= 1);
1101d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1102d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (needThumbnail) {
1103d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // Create a thumbnail whose width is equal or bigger than
1104d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // that of the thumbnail view.
1105d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    int ratio = (int) Math.ceil((double) width / thumbnailWidth);
1106d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    int inSampleSize = Integer.highestOneBit(ratio);
1107d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    Thumbnail t = Thumbnail.createThumbnail(
1108d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                                data, orientation, inSampleSize, uri);
1109d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    synchronized (mUpdateThumbnailLock) {
1110d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        // We need to update the thumbnail in the main thread,
1111d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        // so send a message to run updateThumbnail().
1112d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        mPendingThumbnail = t;
1113d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        mHandler.sendEmptyMessage(UPDATE_THUMBNAIL);
1114d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    }
1115d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1116d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                Util.broadcastNewPicture(mActivity, uri);
1117d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1118d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1119d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1120d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1121d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private static class ImageNamer extends Thread {
1122d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private boolean mRequestPending;
1123d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private ContentResolver mResolver;
1124d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private long mDateTaken;
1125d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private int mWidth, mHeight;
1126d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private boolean mStop;
1127d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private Uri mUri;
1128d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private String mTitle;
1129d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1130d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in main thread
1131d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public ImageNamer() {
1132d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            start();
1133d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1134d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1135d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in main thread
1136d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public synchronized void prepareUri(ContentResolver resolver,
1137d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                long dateTaken, int width, int height, int rotation) {
1138d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (rotation % 180 != 0) {
1139d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                int tmp = width;
1140d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                width = height;
1141d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                height = tmp;
1142d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1143d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mRequestPending = true;
1144d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mResolver = resolver;
1145d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mDateTaken = dateTaken;
1146d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mWidth = width;
1147d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mHeight = height;
1148d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            notifyAll();
1149d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1150d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1151d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in main thread
1152d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public synchronized Uri getUri() {
1153d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // wait until the request is done.
1154d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            while (mRequestPending) {
1155d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                try {
1156d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    wait();
1157d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                } catch (InterruptedException ex) {
1158d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // ignore.
1159d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1160d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1161d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1162d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // return the uri generated
1163d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Uri uri = mUri;
1164d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mUri = null;
1165d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return uri;
1166d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1167d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1168d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in main thread, should be called after getUri().
1169d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public synchronized String getTitle() {
1170d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return mTitle;
1171d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1172d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1173d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in namer thread
1174d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
1175d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public synchronized void run() {
1176d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            while (true) {
1177d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (mStop) break;
1178d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (!mRequestPending) {
1179d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    try {
1180d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        wait();
1181d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    } catch (InterruptedException ex) {
1182d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        // ignore.
1183d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    }
1184d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    continue;
1185d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1186d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                cleanOldUri();
1187d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                generateUri();
1188d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mRequestPending = false;
1189d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                notifyAll();
1190d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1191d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            cleanOldUri();
1192d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1193d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1194d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in main thread
1195d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public synchronized void finish() {
1196d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mStop = true;
1197d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            notifyAll();
1198d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1199d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1200d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in namer thread
1201d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private void generateUri() {
1202d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mTitle = Util.createJpegName(mDateTaken);
1203d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mUri = Storage.newImage(mResolver, mTitle, mDateTaken, mWidth, mHeight);
1204d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1205d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1206d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Runs in namer thread
1207d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        private void cleanOldUri() {
1208d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mUri == null) return;
1209d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Storage.deleteImage(mResolver, mUri);
1210d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mUri = null;
1211d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1212d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1213d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1214d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void setCameraState(int state) {
1215d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraState = state;
1216d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        switch (state) {
1217d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            case PREVIEW_STOPPED:
1218d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            case SNAPSHOT_IN_PROGRESS:
1219d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            case FOCUSING:
1220d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            case SWITCHING_CAMERA:
1221b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb//                enableCameraControls(false);
1222d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                break;
1223d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            case IDLE:
1224b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb//                enableCameraControls(true);
1225d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                break;
1226d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1227d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1228d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1229d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1230d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public boolean capture() {
1231d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // If we are already in the middle of taking a snapshot then ignore.
1232d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
1233d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                || mCameraState == SWITCHING_CAMERA) {
1234d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return false;
1235d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1236d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCaptureStartTime = System.currentTimeMillis();
1237d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPostViewPictureCallbackTime = 0;
1238d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mJpegImageData = null;
1239d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1240d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Set rotation and gps data.
1241d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mJpegRotation = Util.getJpegRotation(mCameraId, mOrientation);
1242d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mParameters.setRotation(mJpegRotation);
1243d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Location loc = mLocationManager.getCurrentLocation();
1244d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Util.setGpsParameters(mParameters, loc);
1245d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraDevice.setParameters(mParameters);
1246d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1247d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback,
1248d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mPostViewPictureCallback, new JpegPictureCallback(loc));
1249d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1250d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Size size = mParameters.getPictureSize();
1251d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mImageNamer.prepareUri(mContentResolver, mCaptureStartTime,
1252d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                size.width, size.height, mJpegRotation);
1253d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1254d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (ApiHelper.HAS_SURFACE_TEXTURE && !mIsImageCaptureIntent) {
1255d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Start capture animation.
1256b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb            ((CameraScreenNail) mActivity.mCameraScreenNail).animateCapture(getCameraRotation());
1257d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1258d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFaceDetectionStarted = false;
1259d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setCameraState(SNAPSHOT_IN_PROGRESS);
1260d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        return true;
1261d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1262d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1263d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int getCameraRotation() {
1264d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        return (mOrientationCompensation - mDisplayRotation + 360) % 360;
1265d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1266d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1267d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1268d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void setFocusParameters() {
1269d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setCameraParameters(UPDATE_PARAM_PREFERENCE);
1270d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1271d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1272d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1273d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void playSound(int soundId) {
1274d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mSoundPlayer.play(soundId);
1275d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1276d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1277d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private int getPreferredCameraId(ComboPreferences preferences) {
1278d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        int intentCameraId = Util.getCameraFacingIntentExtras(mActivity);
1279d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (intentCameraId != -1) {
1280d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Testing purpose. Launch a specific camera through the intent
1281d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // extras.
1282d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return intentCameraId;
1283d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
1284d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return CameraSettings.readPreferredCameraId(preferences);
1285d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1286d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1287d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1288d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1289d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1290d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onFullScreenChanged(boolean full) {
1291d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (ApiHelper.HAS_SURFACE_TEXTURE) return;
1292d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1293d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (full) {
1294d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mPreviewSurfaceView.expand();
1295d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
1296d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mPreviewSurfaceView.shrink();
1297d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1298d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1299d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1300d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1301d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
1302d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Log.v(TAG, "surfaceChanged:" + holder + " width=" + width + ". height="
1303d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                + height);
1304d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1305d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1306d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1307d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void surfaceCreated(SurfaceHolder holder) {
1308d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Log.v(TAG, "surfaceCreated: " + holder);
1309d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraSurfaceHolder = holder;
1310d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Do not access the camera if camera start up thread is not finished.
1311d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mCameraDevice == null || mCameraStartUpThread != null) return;
1312d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1313d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraDevice.setPreviewDisplayAsync(holder);
1314d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // This happens when onConfigurationChanged arrives, surface has been
1315d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // destroyed, and there is no onFullScreenChanged.
1316d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mCameraState == PREVIEW_STOPPED) {
1317d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            setupPreview();
1318d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1319d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1320d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1321d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1322d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void surfaceDestroyed(SurfaceHolder holder) {
1323d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Log.v(TAG, "surfaceDestroyed: " + holder);
1324d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraSurfaceHolder = null;
1325d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        stopPreview();
1326d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1327d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1328d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void updateSceneModeUI() {
1329d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // If scene mode is set, we cannot set flash mode, white balance, and
1330d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // focus mode, instead, we read it from driver
1331d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
1332b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb//            overrideCameraSettings(mParameters.getFlashMode(),
1333b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb//                    mParameters.getWhiteBalance(), mParameters.getFocusMode());
1334d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
1335b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb//            overrideCameraSettings(null, null, null);
1336d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1337d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1338d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1339d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void loadCameraPreferences() {
1340d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        CameraSettings settings = new CameraSettings(mActivity, mInitialParams,
1341d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mCameraId, CameraHolder.instance().getCameraInfo());
1342d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences);
1343d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1344d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1345d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1346d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public boolean collapseCameraControls() {
1347d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        return false;
1348d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1349d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1350d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private class MyOrientationEventListener
1351d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            extends OrientationEventListener {
1352d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public MyOrientationEventListener(Context context) {
1353d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            super(context);
1354d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1355d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1356d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        @Override
1357d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        public void onOrientationChanged(int orientation) {
1358d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // We keep the last known orientation. So if the user first orient
1359d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // the camera then point the camera to floor or sky, we still have
1360d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // the correct orientation.
1361d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (orientation == ORIENTATION_UNKNOWN) return;
1362d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mOrientation = Util.roundOrientation(orientation, mOrientation);
1363d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // When the screen is unlocked, display rotation may change. Always
1364d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // calculate the up-to-date orientationCompensation.
1365d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            int orientationCompensation =
1366d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    (mOrientation + Util.getDisplayRotation(mActivity)) % 360;
1367d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mOrientationCompensation != orientationCompensation) {
1368d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mOrientationCompensation = orientationCompensation;
1369d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                setOrientationIndicator(mOrientationCompensation, true);
1370d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1371d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1372d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Show the toast after getting the first orientation changed.
1373d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) {
1374d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST);
1375d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                showTapToFocusToast();
1376d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1377d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1378d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1379d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1380d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void setOrientationIndicator(int orientation, boolean animation) {
1381d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Rotatable[] indicators = {
1382b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb                mRenderOverlay, mFaceView,
1383d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mReviewDoneButton, mRotateDialog, mOnScreenIndicators};
1384d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        for (Rotatable indicator : indicators) {
1385d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (indicator != null) indicator.setOrientation(orientation, animation);
1386d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1387d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1388d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // We change the orientation of the review cancel button only for tablet
1389d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // UI because there's a label along with the X icon. For phone UI, we
1390d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // don't change the orientation because there's only a symmetrical X
1391d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // icon.
1392d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mReviewCancelButton instanceof RotateLayout) {
1393d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mReviewCancelButton.setOrientation(orientation, animation);
1394d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1395d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1396d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1397d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1398d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onStop() {
1399d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mMediaProviderClient != null) {
1400d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mMediaProviderClient.release();
1401d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mMediaProviderClient = null;
1402d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1403d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1404d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1405d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @OnClickAttr
1406d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onThumbnailClicked(View v) {
1407d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (isCameraIdle() && mActivity.mThumbnail != null) {
1408d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mImageSaver != null) mImageSaver.waitDone();
1409d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mActivity.gotoGallery();
1410d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1411d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1412d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1413d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // onClick handler for R.id.btn_retake
1414d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @OnClickAttr
1415d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onReviewRetakeClicked(View v) {
1416d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mPaused) return;
1417d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1418d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        hidePostCaptureAlert();
1419d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setupPreview();
1420d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1421d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1422d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // onClick handler for R.id.btn_done
1423d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @OnClickAttr
1424d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onReviewDoneClicked(View v) {
1425d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        doAttach();
1426d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1427d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1428d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // onClick handler for R.id.btn_cancel
1429d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @OnClickAttr
1430d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onReviewCancelClicked(View v) {
1431d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        doCancel();
1432d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1433d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1434d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void doAttach() {
1435d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mPaused) {
1436d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
1437d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1438d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1439d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        byte[] data = mJpegImageData;
1440d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1441d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mCropValue == null) {
1442d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // First handle the no crop case -- just return the value.  If the
1443d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // caller specifies a "save uri" then write the data to its
1444d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // stream. Otherwise, pass back a scaled down version of the bitmap
1445d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // directly in the extras.
1446d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mSaveUri != null) {
1447d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                OutputStream outputStream = null;
1448d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                try {
1449d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    outputStream = mContentResolver.openOutputStream(mSaveUri);
1450d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    outputStream.write(data);
1451d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    outputStream.close();
1452d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1453d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mActivity.setResultEx(Activity.RESULT_OK);
1454d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mActivity.finish();
1455d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                } catch (IOException ex) {
1456d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // ignore exception
1457d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                } finally {
1458d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    Util.closeSilently(outputStream);
1459d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1460d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else {
1461d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                int orientation = Exif.getOrientation(data);
1462d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                Bitmap bitmap = Util.makeBitmap(data, 50 * 1024);
1463d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                bitmap = Util.rotate(bitmap, orientation);
1464d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.setResultEx(Activity.RESULT_OK,
1465d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        new Intent("inline-data").putExtra("data", bitmap));
1466d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.finish();
1467d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1468d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
1469d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Save the image to a temp file and invoke the cropper
1470d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Uri tempUri = null;
1471d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            FileOutputStream tempStream = null;
1472d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            try {
1473d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                File path = mActivity.getFileStreamPath(sTempCropFilename);
1474d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                path.delete();
1475d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                tempStream = mActivity.openFileOutput(sTempCropFilename, 0);
1476d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                tempStream.write(data);
1477d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                tempStream.close();
1478d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                tempUri = Uri.fromFile(path);
1479d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } catch (FileNotFoundException ex) {
1480d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.setResultEx(Activity.RESULT_CANCELED);
1481d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.finish();
1482d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                return;
1483d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } catch (IOException ex) {
1484d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.setResultEx(Activity.RESULT_CANCELED);
1485d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.finish();
1486d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                return;
1487d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } finally {
1488d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                Util.closeSilently(tempStream);
1489d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1490d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1491d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Bundle newExtras = new Bundle();
1492d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mCropValue.equals("circle")) {
1493d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                newExtras.putString("circleCrop", "true");
1494d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1495d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mSaveUri != null) {
1496d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
1497d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else {
1498d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                newExtras.putBoolean("return-data", true);
1499d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1500d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1501d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Intent cropIntent = new Intent("com.android.camera.action.CROP");
1502d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1503d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            cropIntent.setData(tempUri);
1504d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            cropIntent.putExtras(newExtras);
1505d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1506d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
1507d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1508d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1509d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1510d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void doCancel() {
1511d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent());
1512d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mActivity.finish();
1513d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1514d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1515d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1516d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onShutterButtonFocus(boolean pressed) {
1517d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mPaused || collapseCameraControls()
1518d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                || (mCameraState == SNAPSHOT_IN_PROGRESS)
1519d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                || (mCameraState == PREVIEW_STOPPED)) return;
1520d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1521d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Do not do focus if there is not enough storage.
1522d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (pressed && !canTakePicture()) return;
1523d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1524d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (pressed) {
1525d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusManager.onShutterDown();
1526d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
1527d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusManager.onShutterUp();
1528d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1529d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1530d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1531d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1532d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onShutterButtonClick() {
1533d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mPaused || collapseCameraControls()
1534d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                || (mCameraState == SWITCHING_CAMERA)
1535d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                || (mCameraState == PREVIEW_STOPPED)) return;
1536d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1537d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Do not take the picture if there is not enough storage.
1538d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mActivity.getStorageSpace() <= Storage.LOW_STORAGE_THRESHOLD) {
1539d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Log.i(TAG, "Not enough space or storage not ready. remaining="
1540d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    + mActivity.getStorageSpace());
1541d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
1542d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1543d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState);
1544d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1545d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // If the user wants to do a snapshot while the previous one is still
1546d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // in progress, remember the fact and do it after we finish the previous
1547d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // one and re-start the preview. Snapshot in progress also includes the
1548d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // state that autofocus is focusing and a picture will be taken when
1549d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // focus callback arrives.
1550d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS)
1551d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                && !mIsImageCaptureIntent) {
1552d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mSnapshotOnIdle = true;
1553d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
1554d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1555d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1556d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mSnapshotOnIdle = false;
1557d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFocusManager.doSnap();
1558d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1559d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1560d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1561d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void installIntentFilter() {
1562d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // install an intent filter to receive SD card related events.
1563d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        IntentFilter intentFilter =
1564d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                new IntentFilter(Intent.ACTION_MEDIA_SCANNER_FINISHED);
1565d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        intentFilter.addDataScheme("file");
1566d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mActivity.registerReceiver(mReceiver, intentFilter);
1567d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mDidRegister = true;
1568d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1569d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1570d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1571d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public boolean updateStorageHintOnResume() {
1572d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        return mFirstTimeInitialized;
1573d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1574d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1575d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1576d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void updateCameraAppView() {
1577d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1578d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1579d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1580d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onResumeBeforeSuper() {
1581d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPaused = false;
1582d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1583d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1584d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1585d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onResumeAfterSuper() {
1586d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mOpenCameraFail || mCameraDisabled) return;
1587d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1588d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mJpegPictureCallbackTime = 0;
1589d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mZoomValue = 0;
1590d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1591d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Start the preview if it is not started.
1592d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mCameraState == PREVIEW_STOPPED && mCameraStartUpThread == null) {
1593d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            resetExposureCompensation();
1594d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraStartUpThread = new CameraStartUpThread();
1595d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraStartUpThread.start();
1596d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1597d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1598d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!mIsImageCaptureIntent) mActivity.getLastThumbnail();
1599d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1600d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // If first time initialization is not finished, put it in the
1601d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // message queue.
1602d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!mFirstTimeInitialized) {
1603d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mHandler.sendEmptyMessage(FIRST_TIME_INIT);
1604d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
1605d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            initializeSecondTime();
1606d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1607d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        keepScreenOnAwhile();
1608d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1609d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Dismiss open menu if exists.
1610d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        PopupManager.getInstance(mActivity).notifyShowPopup(null);
1611d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1612d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mSoundPlayer = SoundClips.getPlayer(mActivity);
1613d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1614d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1615d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    void waitCameraStartUpThread() {
1616d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        try {
1617d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mCameraStartUpThread != null) {
1618d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mCameraStartUpThread.cancel();
1619d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mCameraStartUpThread.join();
1620d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mCameraStartUpThread = null;
1621d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                setCameraState(IDLE);
1622d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1623d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } catch (InterruptedException e) {
1624d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // ignore
1625d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1626d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1627d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1628d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1629d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onPauseBeforeSuper() {
1630d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPaused = true;
1631d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1632d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1633d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1634d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onPauseAfterSuper() {
1635d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Wait the camera start up thread to finish.
1636d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        waitCameraStartUpThread();
1637d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1638d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        stopPreview();
1639d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Close the camera now because other activities may need to use it.
1640d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        closeCamera();
1641d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mSurfaceTexture != null) {
1642b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb            ((CameraScreenNail) mActivity.mCameraScreenNail).releaseSurfaceTexture();
1643d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mSurfaceTexture = null;
1644d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1645d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mSoundPlayer != null) {
1646d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mSoundPlayer.release();
1647d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mSoundPlayer = null;
1648d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1649d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        resetScreenOn();
1650d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1651d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Clear UI.
1652d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        collapseCameraControls();
1653d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFaceView != null) mFaceView.clear();
1654d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1655d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFirstTimeInitialized) {
1656d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mOrientationListener.disable();
1657d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mImageSaver != null) {
1658d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mImageSaver.finish();
1659d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mImageSaver = null;
1660d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mImageNamer.finish();
1661d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mImageNamer = null;
1662d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1663d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1664d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1665d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mDidRegister) {
1666d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mActivity.unregisterReceiver(mReceiver);
1667d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mDidRegister = false;
1668d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1669d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mLocationManager != null) mLocationManager.recordLocation(false);
1670d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        updateExposureOnScreenIndicator(0);
1671d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1672d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // If we are in an image capture intent and has taken
1673d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // a picture, we just clear it in onPause.
1674d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mJpegImageData = null;
1675d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1676d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Remove the messages in the event queue.
1677d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.removeMessages(SETUP_PREVIEW);
1678d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.removeMessages(FIRST_TIME_INIT);
1679d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.removeMessages(CHECK_DISPLAY_ROTATION);
1680d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.removeMessages(SWITCH_CAMERA);
1681d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.removeMessages(SWITCH_CAMERA_START_ANIMATION);
1682d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.removeMessages(CAMERA_OPEN_DONE);
1683d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.removeMessages(START_PREVIEW_DONE);
1684d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.removeMessages(OPEN_CAMERA_FAIL);
1685d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.removeMessages(CAMERA_DISABLED);
1686d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1687d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPendingSwitchCameraId = -1;
1688d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFocusManager != null) mFocusManager.removeMessages();
1689d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1690d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1691d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void initializeControlByIntent() {
1692d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mIsImageCaptureIntent) {
169390ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb            mActivity.hideSwitcher();
1694d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Cannot use RotateImageView for "done" and "cancel" button because
1695d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // the tablet layout uses RotateLayout, which cannot be cast to
1696d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // RotateImageView.
1697d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mReviewDoneButton = (Rotatable) mRootView.findViewById(R.id.btn_done);
1698d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mReviewCancelButton = (Rotatable) mRootView.findViewById(R.id.btn_cancel);
169990ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb
170090ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb            ((View) mReviewCancelButton).setVisibility(View.VISIBLE);
170190ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb
170290ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb            ((View) mReviewDoneButton).setOnClickListener(new OnClickListener() {
170390ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb                @Override
170490ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb                public void onClick(View v) {
170590ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb                    onReviewDoneClicked(v);
170690ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb                }
170790ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb            });
170890ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb            ((View) mReviewCancelButton).setOnClickListener(new OnClickListener() {
170990ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb                @Override
171090ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb                public void onClick(View v) {
171190ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb                    onReviewCancelClicked(v);
171290ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb                }
171390ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb            });
1714d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1715d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Not grayed out upon disabled, to make the follow-up fade-out
1716d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // effect look smooth. Note that the review done button in tablet
1717d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // layout is not a TwoStateImageView.
1718d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mReviewDoneButton instanceof TwoStateImageView) {
1719d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                ((TwoStateImageView) mReviewDoneButton).enableFilter(false);
1720d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1721d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1722d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            setupCaptureParams();
1723d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
1724d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mActivity.mThumbnailView = ((RotateImageView) mRootView.findViewById(R.id.thumbnail));
1725d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mActivity.mThumbnailView != null) {
1726d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.mThumbnailView.enableFilter(false);
1727d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.mThumbnailView.setVisibility(View.VISIBLE);
1728d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.mThumbnailViewWidth = mActivity.mThumbnailView.getLayoutParams().width;
1729d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1730d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mModePicker = (ModePicker) mRootView.findViewById(R.id.mode_picker);
1731d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mModePicker.setVisibility(View.VISIBLE);
1732b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb//                mModePicker.setOnModeChangeListener(this);
1733d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mModePicker.setCurrentMode(ModePicker.MODE_CAMERA);
1734d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1735d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1736d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1737d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1738b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb    /**
1739b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb     * The focus manager is the first UI related element to get initialized,
1740b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb     * and it requires the RenderOverlay, so initialize it here
1741b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb     */
1742d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void initializeFocusManager() {
1743d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Create FocusManager object. startPreview needs it.
1744b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb        mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
1745d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
1746d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
1747d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        String[] defaultFocusModes = mActivity.getResources().getStringArray(
1748d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                R.array.pref_camera_focusmode_default_array);
1749b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb        mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes,
1750b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb                mInitialParams, this, mirror,
1751d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.getMainLooper());
1752d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1753d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1754d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void initializeMiscControls() {
1755d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // startPreview needs this.
1756d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPreviewFrameLayout = (PreviewFrameLayout) mRootView.findViewById(R.id.frame);
1757d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Set touch focus listener.
1758d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mActivity.setSingleTapUpListener(mPreviewFrameLayout);
1759d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1760d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mOnScreenIndicators = (Rotatable) mRootView.findViewById(R.id.on_screen_indicators);
1761d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFaceView = (FaceView) mRootView.findViewById(R.id.face_view);
1762d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPreviewFrameLayout.setOnSizeChangedListener(this);
1763d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPreviewFrameLayout.setOnLayoutChangeListener(mActivity);
1764d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!ApiHelper.HAS_SURFACE_TEXTURE) {
1765d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mPreviewSurfaceView =
1766d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    (PreviewSurfaceView) mRootView.findViewById(R.id.preview_surface_view);
1767d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mPreviewSurfaceView.setVisibility(View.VISIBLE);
1768d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mPreviewSurfaceView.getHolder().addCallback(this);
1769d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1770d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1771d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1772d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1773d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onConfigurationChanged(Configuration newConfig) {
1774d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Log.v(TAG, "onConfigurationChanged");
1775d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setDisplayOrientation();
1776d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1777d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        ((ViewGroup) mRootView).removeAllViews();
1778d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        LayoutInflater inflater = mActivity.getLayoutInflater();
1779d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        inflater.inflate(R.layout.photo_module, (ViewGroup) mRootView);
1780d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1781d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // from onCreate()
1782d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initializeControlByIntent();
1783d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFocusManager != null) mFocusManager.removeMessages();
1784d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initializeFocusManager();
1785d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initializeMiscControls();
1786b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb        loadCameraPreferences();
1787b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb//        initializeIndicatorControl();
1788d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1789d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // from onResume()
1790d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!mIsImageCaptureIntent) mActivity.updateThumbnailView();
1791d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1792d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // from initializeFirstTime()
1793d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mShutterButton = mActivity.getShutterButton();
1794d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mShutterButton.setOnShutterButtonListener(this);
1795d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mShutterButton.setVisibility(View.VISIBLE);
1796d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initializeZoom();
1797d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initOnScreenIndicator();
1798d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        updateOnScreenIndicators();
1799d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFaceView != null) {
1800d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceView.clear();
1801d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceView.setVisibility(View.VISIBLE);
1802d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceView.setDisplayOrientation(mDisplayOrientation);
1803d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
1804d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceView.setMirror(info.facing == CameraInfo.CAMERA_FACING_FRONT);
1805d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceView.resume();
1806d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusManager.setFaceView(mFaceView);
1807d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1808d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1809d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1810d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1811d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onActivityResult(
1812d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            int requestCode, int resultCode, Intent data) {
1813d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        switch (requestCode) {
1814d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            case REQUEST_CROP: {
1815d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                Intent intent = new Intent();
1816d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (data != null) {
1817d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    Bundle extras = data.getExtras();
1818d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    if (extras != null) {
1819d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        intent.putExtras(extras);
1820d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    }
1821d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1822d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.setResultEx(resultCode, intent);
1823d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.finish();
1824d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1825d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                File path = mActivity.getFileStreamPath(sTempCropFilename);
1826d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                path.delete();
1827d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1828d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                break;
1829d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1830d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1831d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1832d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1833d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean canTakePicture() {
1834d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        return isCameraIdle() && (mActivity.getStorageSpace() > Storage.LOW_STORAGE_THRESHOLD);
1835d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1836d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1837d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1838d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void autoFocus() {
1839d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFocusStartTime = System.currentTimeMillis();
1840d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraDevice.autoFocus(mAutoFocusCallback);
1841d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setCameraState(FOCUSING);
1842d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1843d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1844d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1845d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void cancelAutoFocus() {
1846d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraDevice.cancelAutoFocus();
1847d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setCameraState(IDLE);
1848d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setCameraParameters(UPDATE_PARAM_PREFERENCE);
1849d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1850d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1851d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // Preview area is touched. Handle touch focus.
1852d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1853d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onSingleTapUp(View view, int x, int y) {
1854d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mPaused || mCameraDevice == null || !mFirstTimeInitialized
1855d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                || mCameraState == SNAPSHOT_IN_PROGRESS
1856d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                || mCameraState == SWITCHING_CAMERA
1857d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                || mCameraState == PREVIEW_STOPPED) {
1858d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
1859d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1860d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1861d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Do not trigger touch focus if popup window is opened.
1862d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (collapseCameraControls()) return;
1863d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1864d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Check if metering area or focus area is supported.
1865d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!mFocusAreaSupported && !mMeteringAreaSupported) return;
1866d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1867d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFocusManager.onSingleTapUp(x, y);
1868d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1869d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1870d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1871d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public boolean onBackPressed() {
1872d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!isCameraIdle()) {
1873d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // ignore backs while we're taking a picture
1874d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return true;
1875d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
1876d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return collapseCameraControls();
1877d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1878d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1879d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1880d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1881d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public boolean onKeyDown(int keyCode, KeyEvent event) {
1882d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        switch (keyCode) {
1883d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            case KeyEvent.KEYCODE_FOCUS:
1884d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1885d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    onShutterButtonFocus(true);
1886d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1887d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                return true;
1888d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            case KeyEvent.KEYCODE_CAMERA:
1889d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1890d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    onShutterButtonClick();
1891d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1892d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                return true;
1893d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            case KeyEvent.KEYCODE_DPAD_CENTER:
1894d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // If we get a dpad center event without any focused view, move
1895d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // the focus to the shutter button and press it.
1896d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
1897d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // Start auto-focus immediately to reduce shutter lag. After
1898d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // the shutter button gets the focus, onShutterButtonFocus()
1899d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    // will be called again but it is fine.
1900d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    if (collapseCameraControls()) return true;
1901d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    onShutterButtonFocus(true);
1902d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    if (mShutterButton.isInTouchMode()) {
1903d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        mShutterButton.requestFocusFromTouch();
1904d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    } else {
1905d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        mShutterButton.requestFocus();
1906d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    }
1907d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mShutterButton.setPressed(true);
1908d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1909d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                return true;
1910d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1911d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        return false;
1912d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1913d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1914d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
1915d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public boolean onKeyUp(int keyCode, KeyEvent event) {
1916d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        switch (keyCode) {
1917d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            case KeyEvent.KEYCODE_FOCUS:
1918d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (mFirstTimeInitialized) {
1919d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    onShutterButtonFocus(false);
1920d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1921d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                return true;
1922d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1923d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        return false;
1924d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1925d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1926d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
1927d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void closeCamera() {
1928d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mCameraDevice != null) {
1929d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setZoomChangeListener(null);
1930d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if(ApiHelper.HAS_FACE_DETECTION) {
1931d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mCameraDevice.setFaceDetectionListener(null);
1932d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1933d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setErrorCallback(null);
1934d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            CameraHolder.instance().release();
1935d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceDetectionStarted = false;
1936d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice = null;
1937d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            setCameraState(PREVIEW_STOPPED);
1938d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusManager.onCameraReleased();
1939d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1940d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1941d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1942d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void setDisplayOrientation() {
1943d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mDisplayRotation = Util.getDisplayRotation(mActivity);
1944d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId);
1945d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraDisplayOrientation = Util.getDisplayOrientation(0, mCameraId);
1946d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFaceView != null) {
1947d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceView.setDisplayOrientation(mDisplayOrientation);
1948d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1949d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFocusManager.setDisplayOrientation(mDisplayOrientation);
1950d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1951d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1952d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // Only called by UI thread.
1953d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void setupPreview() {
1954d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFocusManager.resetTouchFocus();
1955d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        startPreview();
1956d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setCameraState(IDLE);
1957d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        startFaceDetection();
1958d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
1959d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1960d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // This can be called by UI Thread or CameraStartUpThread. So this should
1961d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // not modify the views.
1962d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void startPreview() {
1963d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraDevice.setErrorCallback(mErrorCallback);
1964d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1965d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // If we're previewing already, stop the preview first (this will blank
1966d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // the screen).
1967d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mCameraState != PREVIEW_STOPPED) stopPreview();
1968d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1969d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setDisplayOrientation();
1970d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1971d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!mSnapshotOnIdle) {
1972d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // If the focus mode is continuous autofocus, call cancelAutoFocus to
1973d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // resume it because it may have been paused by autoFocus call.
1974d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (Util.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
1975d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mCameraDevice.cancelAutoFocus();
1976d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1977d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
1978d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
1979d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setCameraParameters(UPDATE_PARAM_ALL);
1980d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
1981d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (ApiHelper.HAS_SURFACE_TEXTURE) {
1982b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb            CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail;
1983d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mSurfaceTexture == null) {
1984d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                Size size = mParameters.getPreviewSize();
1985d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (mCameraDisplayOrientation % 180 == 0) {
1986d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    screenNail.setSize(size.width, size.height);
1987d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                } else {
1988d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    screenNail.setSize(size.height, size.width);
1989d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
1990d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.notifyScreenNailChanged();
1991d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                screenNail.acquireSurfaceTexture();
1992d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mSurfaceTexture = screenNail.getSurfaceTexture();
1993d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
1994d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
1995d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setPreviewTextureAsync((SurfaceTexture) mSurfaceTexture);
1996d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
1997d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setDisplayOrientation(mDisplayOrientation);
1998d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setPreviewDisplayAsync(mCameraSurfaceHolder);
1999d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2000d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2001d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Log.v(TAG, "startPreview");
2002d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraDevice.startPreviewAsync();
2003d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2004d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFocusManager.onPreviewStarted();
2005d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2006d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mSnapshotOnIdle) {
2007d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mHandler.post(mDoSnapRunnable);
2008d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2009d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2010d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2011d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void stopPreview() {
2012d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
2013d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Log.v(TAG, "stopPreview");
2014d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.cancelAutoFocus(); // Reset the focus.
2015d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.stopPreview();
2016d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFaceDetectionStarted = false;
2017d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2018d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setCameraState(PREVIEW_STOPPED);
2019d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFocusManager != null) mFocusManager.onPreviewStopped();
2020d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2021d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2022d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @SuppressWarnings("deprecation")
2023d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void updateCameraParametersInitialize() {
2024d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Reset preview frame rate to the maximum because it may be lowered by
2025d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // video camera application.
2026d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        List<Integer> frameRates = mParameters.getSupportedPreviewFrameRates();
2027d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (frameRates != null) {
2028d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Integer max = Collections.max(frameRates);
2029d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters.setPreviewFrameRate(max);
2030d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2031d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2032d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mParameters.set(Util.RECORDING_HINT, Util.FALSE);
2033d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2034d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Disable video stabilization. Convenience methods not available in API
2035d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // level <= 14
2036d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        String vstabSupported = mParameters.get("video-stabilization-supported");
2037d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if ("true".equals(vstabSupported)) {
2038d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters.set("video-stabilization", "false");
2039d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2040d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2041d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2042d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void updateCameraParametersZoom() {
2043d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Set zoom.
2044d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mParameters.isZoomSupported()) {
2045d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters.setZoom(mZoomValue);
2046d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2047d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2048d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2049d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2050d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
2051d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void setAutoExposureLockIfSupported() {
2052d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mAeLockSupported) {
2053d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock());
2054d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2055d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2056d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2057d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
2058d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void setAutoWhiteBalanceLockIfSupported() {
2059d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mAwbLockSupported) {
2060d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock());
2061d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2062d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2063d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2064d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
2065d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void setFocusAreasIfSupported() {
2066d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFocusAreaSupported) {
2067d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters.setFocusAreas(mFocusManager.getFocusAreas());
2068d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2069d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2070d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2071d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
2072d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void setMeteringAreasIfSupported() {
2073d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mMeteringAreaSupported) {
2074d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Use the same area for focus and metering.
2075d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
2076d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2077d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2078d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2079d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void updateCameraParametersPreference() {
2080d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setAutoExposureLockIfSupported();
2081d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setAutoWhiteBalanceLockIfSupported();
2082d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setFocusAreasIfSupported();
2083d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setMeteringAreasIfSupported();
2084d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2085d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Set picture size.
2086d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        String pictureSize = mPreferences.getString(
2087d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                CameraSettings.KEY_PICTURE_SIZE, null);
2088d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (pictureSize == null) {
2089d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            CameraSettings.initialCameraPictureSize(mActivity, mParameters);
2090d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
2091d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            List<Size> supported = mParameters.getSupportedPictureSizes();
2092d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            CameraSettings.setCameraPictureSize(
2093d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    pictureSize, supported, mParameters);
2094d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2095d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Size size = mParameters.getPictureSize();
2096d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2097d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Set a preview size that is closest to the viewfinder height and has
2098d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // the right aspect ratio.
2099d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        List<Size> sizes = mParameters.getSupportedPreviewSizes();
2100d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Size optimalSize = Util.getOptimalPreviewSize(mActivity, sizes,
2101d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                (double) size.width / size.height);
2102d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Size original = mParameters.getPreviewSize();
2103d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (!original.equals(optimalSize)) {
2104d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
2105d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2106d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Zoom related settings will be changed for different preview
2107d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // sizes, so set and read the parameters to get latest values
2108d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setParameters(mParameters);
2109d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters = mCameraDevice.getParameters();
2110d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2111d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height);
2112d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2113d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Since change scene mode may change supported values,
2114d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Set scene mode first,
2115d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mSceneMode = mPreferences.getString(
2116d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                CameraSettings.KEY_SCENE_MODE,
2117d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.getString(R.string.pref_camera_scenemode_default));
2118d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (Util.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
2119d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (!mParameters.getSceneMode().equals(mSceneMode)) {
2120d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mParameters.setSceneMode(mSceneMode);
2121d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2122d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // Setting scene mode will change the settings of flash mode,
2123d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // white balance, and focus mode. Here we read back the
2124d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                // parameters, so we can know those settings.
2125d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mCameraDevice.setParameters(mParameters);
2126d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mParameters = mCameraDevice.getParameters();
2127d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
2128d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
2129d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mSceneMode = mParameters.getSceneMode();
2130d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (mSceneMode == null) {
2131d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mSceneMode = Parameters.SCENE_MODE_AUTO;
2132d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
2133d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2134d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2135d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Set JPEG quality.
2136d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
2137d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                CameraProfile.QUALITY_HIGH);
2138d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mParameters.setJpegQuality(jpegQuality);
2139d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2140d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // For the following settings, we need to check if the settings are
2141d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // still supported by latest driver, if not, ignore the settings.
2142d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2143d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Set exposure compensation
2144d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        int value = CameraSettings.readExposure(mPreferences);
2145d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        int max = mParameters.getMaxExposureCompensation();
2146d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        int min = mParameters.getMinExposureCompensation();
2147d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (value >= min && value <= max) {
2148d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters.setExposureCompensation(value);
2149d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
2150d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Log.w(TAG, "invalid exposure range: " + value);
2151d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2152d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2153d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) {
2154d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Set flash mode.
2155d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            String flashMode = mPreferences.getString(
2156d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    CameraSettings.KEY_FLASH_MODE,
2157d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mActivity.getString(R.string.pref_camera_flashmode_default));
2158d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            List<String> supportedFlash = mParameters.getSupportedFlashModes();
2159d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (Util.isSupported(flashMode, supportedFlash)) {
2160d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mParameters.setFlashMode(flashMode);
2161d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else {
2162d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                flashMode = mParameters.getFlashMode();
2163d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (flashMode == null) {
2164d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    flashMode = mActivity.getString(
2165d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                            R.string.pref_camera_flashmode_no_flash);
2166d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
2167d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
2168d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2169d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Set white balance parameter.
2170d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            String whiteBalance = mPreferences.getString(
2171d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    CameraSettings.KEY_WHITE_BALANCE,
2172d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mActivity.getString(R.string.pref_camera_whitebalance_default));
2173d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (Util.isSupported(whiteBalance,
2174d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    mParameters.getSupportedWhiteBalance())) {
2175d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mParameters.setWhiteBalance(whiteBalance);
2176d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            } else {
2177d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                whiteBalance = mParameters.getWhiteBalance();
2178d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                if (whiteBalance == null) {
2179d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                    whiteBalance = Parameters.WHITE_BALANCE_AUTO;
2180d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                }
2181d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
2182d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2183d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Set focus mode.
2184d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusManager.overrideFocusMode(null);
2185d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mParameters.setFocusMode(mFocusManager.getFocusMode());
2186d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
2187d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mFocusManager.overrideFocusMode(mParameters.getFocusMode());
2188d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2189d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2190d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mContinousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) {
2191d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            updateAutoFocusMoveCallback();
2192d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2193d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2194d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2195d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
2196d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void updateAutoFocusMoveCallback() {
2197d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mParameters.getFocusMode().equals(Util.FOCUS_MODE_CONTINUOUS_PICTURE)) {
2198d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setAutoFocusMoveCallback(
2199d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                (AutoFocusMoveCallback) mAutoFocusMoveCallback);
2200d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
2201d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCameraDevice.setAutoFocusMoveCallback(null);
2202d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2203d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2204d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2205d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // We separate the parameters into several subsets, so we can update only
2206d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // the subsets actually need updating. The PREFERENCE set needs extra
2207d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // locking because the preference can be changed from GLThread as well.
2208d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void setCameraParameters(int updateSet) {
2209d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
2210d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            updateCameraParametersInitialize();
2211d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2212d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2213d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
2214d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            updateCameraParametersZoom();
2215d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2216d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2217d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
2218d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            updateCameraParametersPreference();
2219d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2220d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2221d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraDevice.setParameters(mParameters);
2222d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2223d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2224d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // If the Camera is idle, update the parameters immediately, otherwise
2225d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // accumulate them in mUpdateSet and update later.
2226d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void setCameraParametersWhenIdle(int additionalUpdateSet) {
2227d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mUpdateSet |= additionalUpdateSet;
2228d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mCameraDevice == null) {
2229d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // We will update all the parameters when we open the device, so
2230d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // we don't need to do anything now.
2231d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mUpdateSet = 0;
2232d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            return;
2233d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else if (isCameraIdle()) {
2234d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            setCameraParameters(mUpdateSet);
2235d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            updateSceneModeUI();
2236d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mUpdateSet = 0;
2237d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
2238d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) {
2239d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mHandler.sendEmptyMessageDelayed(
2240d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000);
2241d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
2242d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2243d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2244d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2245d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean isCameraIdle() {
2246d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        return (mCameraState == IDLE) ||
2247d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                ((mFocusManager != null) && mFocusManager.isFocusCompleted()
2248d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                        && (mCameraState != SWITCHING_CAMERA));
2249d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2250d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2251d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private boolean isImageCaptureIntent() {
2252d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        String action = mActivity.getIntent().getAction();
2253d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action));
2254d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2255d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2256d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void setupCaptureParams() {
2257d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Bundle myExtras = mActivity.getIntent().getExtras();
2258d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (myExtras != null) {
2259d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
2260d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mCropValue = myExtras.getString("crop");
2261d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2262d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2263d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2264d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void showPostCaptureAlert() {
2265d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mIsImageCaptureIntent) {
2266d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Util.fadeOut(mShutterButton);
2267d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
226890ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb//            Util.fadeIn(mReviewRetakeButton);
2269d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Util.fadeIn((View) mReviewDoneButton);
2270d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2271d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2272d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2273d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void hidePostCaptureAlert() {
2274d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mIsImageCaptureIntent) {
227590ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb//            Util.fadeOut(mReviewRetakeButton);
2276d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Util.fadeOut((View) mReviewDoneButton);
2277d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2278d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Util.fadeIn(mShutterButton);
2279d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2280d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2281d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2282d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
2283d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onSharedPreferenceChanged() {
2284d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // ignore the events after "onPause()"
2285d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mPaused) return;
2286d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2287d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        boolean recordLocation = RecordLocationPreference.get(
2288d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mPreferences, mContentResolver);
2289d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mLocationManager.recordLocation(recordLocation);
2290d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2291d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE);
2292d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setPreviewFrameLayoutAspectRatio();
2293d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        updateOnScreenIndicators();
2294d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2295d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2296d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
2297d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onCameraPickerClicked(int cameraId) {
2298d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mPaused || mPendingSwitchCameraId != -1) return;
2299d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2300d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPendingSwitchCameraId = cameraId;
2301d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (ApiHelper.HAS_SURFACE_TEXTURE) {
2302d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            Log.v(TAG, "Start to copy texture. cameraId=" + cameraId);
2303d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // We need to keep a preview frame for the animation before
2304d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // releasing the camera. This will trigger onPreviewTextureCopied.
2305b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb            ((CameraScreenNail) mActivity.mCameraScreenNail).copyTexture();
2306d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Disable all camera controls.
2307d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            setCameraState(SWITCHING_CAMERA);
2308d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } else {
2309d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            switchCamera();
2310d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2311d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2312d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2313d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void switchCamera() {
2314d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mPaused) return;
2315d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2316d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
2317d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mCameraId = mPendingSwitchCameraId;
2318d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPendingSwitchCameraId = -1;
2319b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb//        mCameraPicker.setCameraId(mCameraId);
2320d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2321d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // from onPause
2322d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        closeCamera();
2323d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        collapseCameraControls();
2324d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFaceView != null) mFaceView.clear();
2325d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFocusManager != null) mFocusManager.removeMessages();
2326d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2327d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Restart the camera and initialize the UI. From onCreate.
2328d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPreferences.setLocalId(mActivity, mCameraId);
2329d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
2330d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        CameraOpenThread cameraOpenThread = new CameraOpenThread();
2331d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        cameraOpenThread.start();
2332d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        try {
2333d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            cameraOpenThread.join();
2334d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        } catch (InterruptedException ex) {
2335d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // ignore
2336d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2337d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initializeCapabilities();
2338d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
2339d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
2340d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFocusManager.setMirror(mirror);
2341d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFocusManager.setParameters(mInitialParams);
2342d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setupPreview();
2343b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb        loadCameraPreferences();
2344b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb//        initializeIndicatorControl();
2345d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2346d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // from onResume
2347d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        setOrientationIndicator(mOrientationCompensation, false);
2348d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // from initializeFirstTime
2349d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        initializeZoom();
2350d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        updateOnScreenIndicators();
2351d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        showTapToFocusToastIfNeeded();
2352d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2353d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (ApiHelper.HAS_SURFACE_TEXTURE) {
2354d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // Start switch camera animation. Post a message because
2355d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            // onFrameAvailable from the old camera may already exist.
2356d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
2357d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2358d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2359d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2360d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // Preview texture has been copied. Now camera can be released and the
2361d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // animation can be started.
2362d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
2363d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onPreviewTextureCopied() {
2364d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.sendEmptyMessage(SWITCH_CAMERA);
2365d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2366d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2367d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
2368d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onUserInteraction() {
2369fe269902ba8522e01baa9be45755779f050c1d6cWu-cheng Li        if (!mActivity.isFinishing()) keepScreenOnAwhile();
2370d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2371d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2372d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void resetScreenOn() {
2373d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.removeMessages(CLEAR_SCREEN_DELAY);
2374d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
2375d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2376d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2377d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void keepScreenOnAwhile() {
2378d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.removeMessages(CLEAR_SCREEN_DELAY);
2379d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
2380d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
2381d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2382d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2383d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
2384d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onRestorePreferencesClicked() {
2385d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mPaused) return;
2386d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Runnable runnable = new Runnable() {
2387d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            @Override
2388d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            public void run() {
2389d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                restorePreferences();
2390d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            }
2391d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        };
2392d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mRotateDialog.showAlertDialog(
2393d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                null,
2394d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.getString(R.string.confirm_restore_message),
2395d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.getString(android.R.string.ok), runnable,
2396d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                mActivity.getString(android.R.string.cancel), null);
2397d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2398d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2399d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void restorePreferences() {
2400d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Reset the zoom. Zoom value is not stored in preference.
2401d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mParameters.isZoomSupported()) {
2402d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mZoomValue = 0;
2403d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            setCameraParametersWhenIdle(UPDATE_PARAM_ZOOM);
2404b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb            // TODO: reset zoom
2405d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2406b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb        CameraSettings.restorePreferences(mActivity, mPreferences,
2407b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb                mParameters);
2408b19c713286b7beed376ec6c4390e7272a80aa5b9Michael Kolb        onSharedPreferenceChanged();
2409d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2410d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2411d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
2412d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onOverriddenPreferencesClicked() {
2413d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mPaused) return;
2414d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mNotSelectableToast == null) {
2415d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            String str = mActivity.getResources().getString(R.string.not_selectable_in_scene_mode);
2416d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb            mNotSelectableToast = Toast.makeText(mActivity, str, Toast.LENGTH_SHORT);
2417d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        }
2418d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mNotSelectableToast.show();
2419d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2420d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2421d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void showTapToFocusToast() {
2422d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        new RotateTextToast(mActivity, R.string.tap_to_focus, mOrientationCompensation).show();
2423d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Clear the preference.
2424d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Editor editor = mPreferences.edit();
2425d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        editor.putBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, false);
2426d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        editor.apply();
2427d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2428d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2429d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    private void initializeCapabilities() {
2430d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mInitialParams = mCameraDevice.getParameters();
2431d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mFocusAreaSupported = Util.isFocusAreaSupported(mInitialParams);
2432d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mMeteringAreaSupported = Util.isMeteringAreaSupported(mInitialParams);
2433d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mAeLockSupported = Util.isAutoExposureLockSupported(mInitialParams);
2434d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mAwbLockSupported = Util.isAutoWhiteBalanceLockSupported(mInitialParams);
2435d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mContinousFocusSupported = mInitialParams.getSupportedFocusModes().contains(
2436d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb                Util.FOCUS_MODE_CONTINUOUS_PICTURE);
2437d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2438d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2439d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    // PreviewFrameLayout size has changed.
2440d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    @Override
2441d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    public void onSizeChanged(int width, int height) {
2442d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        if (mFocusManager != null) mFocusManager.setPreviewSize(width, height);
2443d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2444d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
2445d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    void setPreviewFrameLayoutAspectRatio() {
2446d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        // Set the preview frame aspect ratio according to the picture size.
2447d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        Size size = mParameters.getPictureSize();
2448d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb        mPreviewFrameLayout.setAspectRatio((double) size.width / size.height);
2449d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb    }
2450d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb
245190ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb    @Override
245290ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb    public boolean needsSwitcher() {
245390ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb        return !mIsImageCaptureIntent;
245490ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb    }
245590ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb
2456d3a252bb71d119cbaeff55aeaa27dd1f8adadba2Michael Kolb}
2457