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