blob: 45a2f9b38d45879df8f7284eeca73a8926236bbf [file] [log] [blame]
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera;
18
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080019import android.app.Activity;
Owen Lin0e841fe2009-04-09 07:41:20 -070020import android.content.ActivityNotFoundException;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080021import android.content.BroadcastReceiver;
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.SharedPreferences;
Owen Lin2c6c6172009-09-01 14:51:53 +080027import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
Owen Lin3f3c8572009-08-18 13:33:49 +080028import android.content.res.Resources;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080029import android.graphics.Bitmap;
30import android.graphics.BitmapFactory;
Wu-cheng Li4305c702009-09-02 16:33:59 +080031import android.hardware.Camera.Parameters;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080032import android.hardware.Camera.PictureCallback;
Wu-cheng Li4305c702009-09-02 16:33:59 +080033import android.hardware.Camera.Size;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080034import android.location.Location;
35import android.location.LocationManager;
36import android.location.LocationProvider;
37import android.media.AudioManager;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080038import android.media.ToneGenerator;
39import android.net.Uri;
Owen Linf6ef7b92009-09-14 18:48:12 +080040import android.os.Build;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080041import android.os.Bundle;
42import android.os.Debug;
43import android.os.Environment;
44import android.os.Handler;
45import android.os.Message;
46import android.os.SystemClock;
47import android.preference.PreferenceManager;
48import android.provider.MediaStore;
49import android.text.format.DateFormat;
Chih-Chung Chang5e5aa7e2009-04-21 18:24:13 +080050import android.util.AttributeSet;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080051import android.util.Log;
Cheng-Ru Lin542fa892009-10-03 02:05:13 +080052import android.view.Display;
Wu-cheng Liaa3cc202009-09-03 16:28:22 +080053import android.view.GestureDetector;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080054import android.view.KeyEvent;
Owen Lin61b98312009-06-19 00:21:10 -070055import android.view.LayoutInflater;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080056import android.view.Menu;
57import android.view.MenuItem;
Wu-cheng Li95fc5b22009-06-06 16:53:44 +080058import android.view.MotionEvent;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080059import android.view.OrientationEventListener;
60import android.view.SurfaceHolder;
Cheng-Ru Linffcca742009-09-28 03:21:25 +080061import android.view.SurfaceView;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080062import android.view.View;
63import android.view.ViewGroup;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080064import android.view.Window;
65import android.view.WindowManager;
Owen Lin0ce26e02009-05-05 15:43:54 -070066import android.view.MenuItem.OnMenuItemClickListener;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080067import android.widget.ImageView;
Wu-cheng Li35bda2d2009-09-27 20:45:42 -070068import android.widget.ZoomButtonsController;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080069
Owen Lin2e768c12009-07-01 15:51:45 -070070import com.android.camera.gallery.IImage;
71import com.android.camera.gallery.IImageList;
72
Owen Lin0e841fe2009-04-09 07:41:20 -070073import java.io.File;
74import java.io.FileNotFoundException;
75import java.io.FileOutputStream;
76import java.io.IOException;
77import java.io.OutputStream;
78import java.util.ArrayList;
Wu-cheng Licc5a6352009-09-08 12:21:52 +080079import java.util.Collections;
Wu-cheng Li4305c702009-09-02 16:33:59 +080080import java.util.List;
Owen Lin0e841fe2009-04-09 07:41:20 -070081
82/**
83 * Activity of the Camera which used to see preview and take pictures.
84 */
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080085public class Camera extends Activity implements View.OnClickListener,
Owen Line239acc2009-06-23 22:18:20 -070086 ShutterButton.OnShutterButtonListener, SurfaceHolder.Callback,
Owen Lina4e3d272009-09-17 14:45:06 +080087 Switcher.OnSwitchListener, OnScreenSettings.OnVisibilityChangedListener,
Owen Lin2c6c6172009-09-01 14:51:53 +080088 OnSharedPreferenceChangeListener {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080089
90 private static final String TAG = "camera";
91
Owen Lin12f4b9a2009-10-05 18:13:06 -070092 // This value must be as same as the item value of the string array
93 // "flash_mode" in file "res/values/arrays.xml".
94 private static final String NO_FLASH_MODE = "no_flash";
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080095 private static final int CROP_MSG = 1;
Wu-cheng Lie43adb12009-05-14 11:31:41 +080096 private static final int FIRST_TIME_INIT = 2;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -080097 private static final int RESTART_PREVIEW = 3;
98 private static final int CLEAR_SCREEN_DELAY = 4;
99
Owen Lin37acf792009-09-17 17:55:37 +0800100 private static final String GPS_MODE_ON = "on";
101 private static final String GPS_MODE_OFF = "off";
102
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800103 private static final int SCREEN_DELAY = 2 * 60 * 1000;
104 private static final int FOCUS_BEEP_VOLUME = 100;
105
Cheng-Ru Lin25156f02009-10-01 00:34:41 +0800106 private static final String SCENE_MODE_ON = "on";
107 private static final String SCENE_MODE_OFF = "off";
Cheng-Ru Lin27e69922009-09-30 13:48:59 +0800108
Wu-cheng Li35bda2d2009-09-27 20:45:42 -0700109 private double mZoomValue; // The current zoom value.
110 private double mZoomStep;
111 private double mZoomMax;
112 public static final double ZOOM_STEP_MIN = 0.25;
113 public static final String ZOOM_STOP = "stop";
114 public static final String ZOOM_IMMEDIATE = "zoom-immediate";
115 public static final String ZOOM_CONTINUOUS = "zoom-continuous";
116 public static final double ZOOM_MIN = 1.0;
117 public static final String ZOOM_SPEED = "99";
118
President Li5f6484a2009-04-02 02:38:09 -0700119 private Parameters mParameters;
Cheng-Ru Lindf3731b2009-10-02 08:37:21 +0800120 private Parameters mInitialParameters;
President Li5f6484a2009-04-02 02:38:09 -0700121
Wu-cheng Li35bda2d2009-09-27 20:45:42 -0700122 // The non-standard parameter strings to communicate with camera driver.
123 // This will be removed in the future.
124 public static final String PARM_ZOOM_STATE = "mot-zoom-state";
125 public static final String PARM_ZOOM_STEP = "mot-zoom-step";
126 public static final String PARM_ZOOM_TO_LEVEL = "mot-zoom-to-level";
127 public static final String PARM_ZOOM_SPEED = "mot-zoom-speed";
128 public static final String PARM_ZOOM_MAX = "mot-max-picture-continuous-zoom";
129
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800130 private OrientationEventListener mOrientationListener;
131 private int mLastOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
132 private SharedPreferences mPreferences;
133
134 private static final int IDLE = 1;
135 private static final int SNAPSHOT_IN_PROGRESS = 2;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800136
Owen Line239acc2009-06-23 22:18:20 -0700137 private static final boolean SWITCH_CAMERA = true;
138 private static final boolean SWITCH_VIDEO = false;
139
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800140 private int mStatus = IDLE;
141 private static final String sTempCropFilename = "crop-temp";
142
143 private android.hardware.Camera mCameraDevice;
Cheng-Ru Linffcca742009-09-28 03:21:25 +0800144 private SurfaceView mSurfaceView;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800145 private SurfaceHolder mSurfaceHolder = null;
Wu-cheng Li95fc5b22009-06-06 16:53:44 +0800146 private ShutterButton mShutterButton;
147 private FocusRectangle mFocusRectangle;
Owen Lin37acf792009-09-17 17:55:37 +0800148 private IconIndicator mGpsIndicator;
149 private IconIndicator mFlashIndicator;
Cheng-Ru Lin27e69922009-09-30 13:48:59 +0800150 private IconIndicator mFocusIndicator;
151 private IconIndicator mWhitebalanceIndicator;
Cheng-Ru Lin25156f02009-10-01 00:34:41 +0800152 private IconIndicator mSceneModeIndicator;
Wu-cheng Li95fc5b22009-06-06 16:53:44 +0800153 private ToneGenerator mFocusToneGenerator;
Wu-cheng Li35bda2d2009-09-27 20:45:42 -0700154 private ZoomButtonsController mZoomButtons;
Wu-cheng Liaa3cc202009-09-03 16:28:22 +0800155 private GestureDetector mGestureDetector;
Owen Lin2e768c12009-07-01 15:51:45 -0700156 private Switcher mSwitcher;
Owen Lin3f3c8572009-08-18 13:33:49 +0800157 private boolean mStartPreviewFail = false;
Wu-cheng Li95fc5b22009-06-06 16:53:44 +0800158
159 // mPostCaptureAlert, mLastPictureButton, mThumbController
160 // are non-null only if isImageCaptureIntent() is true.
Wu-cheng Li95fc5b22009-06-06 16:53:44 +0800161 private ImageView mLastPictureButton;
162 private ThumbnailController mThumbController;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800163
Chih-Chung Changc30e5c22009-09-23 16:02:30 -0700164 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
Chih-Chung Changcd972b02009-09-22 16:47:43 -0700165 private String mCropValue;
166 private Uri mSaveUri;
Chih-Chung Changcd972b02009-09-22 16:47:43 -0700167
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800168 private ImageCapture mImageCapture = null;
169
Wu-cheng Li95fc5b22009-06-06 16:53:44 +0800170 private boolean mPreviewing;
171 private boolean mPausing;
172 private boolean mFirstTimeInitialized;
Wu-cheng Li95fc5b22009-06-06 16:53:44 +0800173 private boolean mIsImageCaptureIntent;
174 private boolean mRecordLocation;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800175
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800176 private static final int FOCUS_NOT_STARTED = 0;
177 private static final int FOCUSING = 1;
178 private static final int FOCUSING_SNAP_ON_FINISH = 2;
179 private static final int FOCUS_SUCCESS = 3;
180 private static final int FOCUS_FAIL = 4;
181 private int mFocusState = FOCUS_NOT_STARTED;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800182
Owen Lin0e841fe2009-04-09 07:41:20 -0700183 private ContentResolver mContentResolver;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800184 private boolean mDidRegister = false;
185
Owen Linbbc560b2009-04-17 11:31:27 +0800186 private final ArrayList<MenuItem> mGalleryItems = new ArrayList<MenuItem>();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800187
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800188 private LocationManager mLocationManager = null;
189
Wu-cheng Libcd13fa2009-04-20 18:12:41 +0800190 // Use OneShotPreviewCallback to measure the time between
191 // JpegPictureCallback and preview.
192 private final OneShotPreviewCallback mOneShotPreviewCallback =
193 new OneShotPreviewCallback();
Owen Linbbc560b2009-04-17 11:31:27 +0800194 private final ShutterCallback mShutterCallback = new ShutterCallback();
Wu-cheng Libcd13fa2009-04-20 18:12:41 +0800195 private final RawPictureCallback mRawPictureCallback =
196 new RawPictureCallback();
197 private final AutoFocusCallback mAutoFocusCallback =
198 new AutoFocusCallback();
Wu-cheng Li35bda2d2009-09-27 20:45:42 -0700199 private final ZoomCallback mZoomCallback = new ZoomCallback();
Yu Shan Emily Laucede87f2009-07-02 18:07:17 -0700200 // Use the ErrorCallback to capture the crash count
201 // on the mediaserver
202 private final ErrorCallback mErrorCallback = new ErrorCallback();
203
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800204 private long mFocusStartTime;
205 private long mFocusCallbackTime;
206 private long mCaptureStartTime;
207 private long mShutterCallbackTime;
208 private long mRawPictureCallbackTime;
Wu-cheng Libcd13fa2009-04-20 18:12:41 +0800209 private long mJpegPictureCallbackTime;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800210 private int mPicturesRemaining;
211
Chih-Chung Chang0a285492009-07-03 18:25:26 +0800212 // These latency time are for the CameraLatency test.
213 public long mAutoFocusTime;
214 public long mShutterLag;
215 public long mShutterAndRawPictureCallbackTime;
216 public long mJpegPictureCallbackTimeLag;
217 public long mRawPictureAndJpegPictureCallbackTime;
Yu Shan Emily Lau11cac262009-06-02 21:59:58 -0700218
Chih-Chung Chang9b93bcb2009-09-04 19:46:14 +0800219 // Add the media server tag
Yu Shan Emily Laucede87f2009-07-02 18:07:17 -0700220 public static boolean mMediaServerDied = false;
Wu-cheng Li0f56ef52009-04-15 17:47:56 +0800221 // Focus mode. Options are pref_camera_focusmode_entryvalues.
222 private String mFocusMode;
223
Owen Linbbc560b2009-04-17 11:31:27 +0800224 private final Handler mHandler = new MainHandler();
Owen Lin2c6c6172009-09-01 14:51:53 +0800225 private OnScreenSettings mSettings;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800226
Owen Lin0e841fe2009-04-09 07:41:20 -0700227 /**
228 * This Handler is used to post message back onto the main thread of the
229 * application
230 */
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800231 private class MainHandler extends Handler {
232 @Override
233 public void handleMessage(Message msg) {
234 switch (msg.what) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800235 case RESTART_PREVIEW: {
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +0800236 restartPreview();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800237 break;
238 }
239
240 case CLEAR_SCREEN_DELAY: {
Owen Lin0e841fe2009-04-09 07:41:20 -0700241 getWindow().clearFlags(
242 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800243 break;
244 }
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800245
246 case FIRST_TIME_INIT: {
247 initializeFirstTime();
248 break;
249 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800250 }
251 }
Owen Lin937fc482009-04-14 02:02:51 -0700252 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800253
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +0800254 // Snapshots can only be taken after this is called. It should be called
255 // once only. We could have done these things in onCreate() but we want to
256 // make preview screen appear as soon as possible.
Chih-Chung Chang522e8362009-08-26 16:12:34 +0800257 private void initializeFirstTime() {
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800258 if (mFirstTimeInitialized) return;
259
260 // Create orientation listenter. This should be done first because it
261 // takes some time to get first orientation.
262 mOrientationListener =
263 new OrientationEventListener(Camera.this) {
264 @Override
265 public void onOrientationChanged(int orientation) {
266 // We keep the last known orientation. So if the user
267 // first orient the camera then point the camera to
268 // floor/sky, we still have the correct orientation.
269 if (orientation != ORIENTATION_UNKNOWN) {
270 mLastOrientation = orientation;
271 }
272 }
273 };
274 mOrientationListener.enable();
275
276 // Initialize location sevice.
277 mLocationManager = (LocationManager)
278 getSystemService(Context.LOCATION_SERVICE);
279 readPreference();
280 if (mRecordLocation) startReceivingLocationUpdates();
281
Wu-cheng Lid12ae202009-07-27 17:44:56 +0800282 checkStorage();
283
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800284 // Initialize last picture button.
285 mContentResolver = getContentResolver();
286 if (!mIsImageCaptureIntent) {
Owen Lindad4b182009-06-11 16:02:29 -0700287 findViewById(R.id.camera_switch).setOnClickListener(this);
288 mLastPictureButton =
289 (ImageView) findViewById(R.id.review_thumbnail);
Owen Lin059daa32009-05-18 15:31:17 -0700290 mLastPictureButton.setOnClickListener(this);
291 mThumbController = new ThumbnailController(
Owen Line594b192009-08-13 18:04:45 +0800292 getResources(), mLastPictureButton, mContentResolver);
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800293 mThumbController.loadData(ImageManager.getLastImageThumbPath());
Owen Lin059daa32009-05-18 15:31:17 -0700294 // Update last image thumbnail.
repo sync547caa32009-06-15 16:11:09 +0800295 updateThumbnailButton();
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800296 }
297
298 // Initialize shutter button.
Owen Lindad4b182009-06-11 16:02:29 -0700299 mShutterButton = (ShutterButton) findViewById(R.id.shutter_button);
Owen Lin059daa32009-05-18 15:31:17 -0700300 mShutterButton.setOnShutterButtonListener(this);
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800301 mShutterButton.setVisibility(View.VISIBLE);
302
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800303 mFocusRectangle = (FocusRectangle) findViewById(R.id.focus_rectangle);
304 updateFocusIndicator();
305
306 // Initialize GPS indicator.
Owen Lin37acf792009-09-17 17:55:37 +0800307 mGpsIndicator = (IconIndicator) findViewById(R.id.gps_icon);
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800308
309 ImageManager.ensureOSXCompatibleFolder();
310
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800311 installIntentFilter();
312
313 initializeFocusTone();
314
Wu-cheng Li35bda2d2009-09-27 20:45:42 -0700315 initializeZoom();
316
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800317 mFirstTimeInitialized = true;
318 }
319
repo sync547caa32009-06-15 16:11:09 +0800320 private void updateThumbnailButton() {
Wu-cheng Lid12ae202009-07-27 17:44:56 +0800321 // Update last image if URI is invalid and the storage is ready.
322 if (!mThumbController.isUriValid() && mPicturesRemaining >= 0) {
repo sync547caa32009-06-15 16:11:09 +0800323 updateLastImage();
324 }
325 mThumbController.updateDisplayIfNeeded();
326 }
327
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800328 // If the activity is paused and resumed, this method will be called in
329 // onResume.
Chih-Chung Chang522e8362009-08-26 16:12:34 +0800330 private void initializeSecondTime() {
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800331 // Start orientation listener as soon as possible because it takes
332 // some time to get first orientation.
333 mOrientationListener.enable();
334
335 // Start location update if needed.
336 readPreference();
337 if (mRecordLocation) startReceivingLocationUpdates();
338
339 installIntentFilter();
340
341 initializeFocusTone();
repo sync547caa32009-06-15 16:11:09 +0800342
Wu-cheng Lid12ae202009-07-27 17:44:56 +0800343 checkStorage();
344
Wu-cheng Li35bda2d2009-09-27 20:45:42 -0700345 if (mZoomButtons != null) {
346 mZoomValue = Double.parseDouble(
347 mParameters.get(PARM_ZOOM_TO_LEVEL));
348 mCameraDevice.setZoomCallback(mZoomCallback);
349 }
350
repo sync547caa32009-06-15 16:11:09 +0800351 if (!mIsImageCaptureIntent) {
352 updateThumbnailButton();
353 }
Wu-cheng Lie43adb12009-05-14 11:31:41 +0800354 }
355
Wu-cheng Li35bda2d2009-09-27 20:45:42 -0700356 private void initializeZoom() {
357 // Check if the phone has zoom capability.
358 String zoomState = mParameters.get(PARM_ZOOM_STATE);
359 if (zoomState == null) return;
360
361 mZoomValue = Double.parseDouble(mParameters.get(PARM_ZOOM_TO_LEVEL));
362 mZoomMax = Double.parseDouble(mParameters.get(PARM_ZOOM_MAX));
363 mZoomStep = Double.parseDouble(mParameters.get(PARM_ZOOM_STEP));
364 mParameters.set(PARM_ZOOM_SPEED, ZOOM_SPEED);
365 mCameraDevice.setParameters(mParameters);
366
367 mGestureDetector = new GestureDetector(this, new ZoomGestureListener());
368 mCameraDevice.setZoomCallback(mZoomCallback);
369 mZoomButtons = new ZoomButtonsController(mSurfaceView);
370 mZoomButtons.setAutoDismissed(true);
371 mZoomButtons.setZoomSpeed(100);
372 mZoomButtons.setOnZoomListener(
373 new ZoomButtonsController.OnZoomListener() {
374 public void onVisibilityChanged(boolean visible) {
375 if (visible) {
376 updateZoomButtonsEnabled();
377 }
378 }
379
380 public void onZoom(boolean zoomIn) {
381 if (isZooming()) return;
382
383 if (zoomIn) {
384 if (mZoomValue < mZoomMax) {
385 zoomToLevel(ZOOM_CONTINUOUS, mZoomValue + mZoomStep);
386 }
387 } else {
388 if (mZoomValue > ZOOM_MIN) {
389 zoomToLevel(ZOOM_CONTINUOUS, mZoomValue - mZoomStep);
390 }
391 }
392 }
393 });
394 }
395
Owen Linc1f2e302009-09-14 19:04:37 +0800396 public void onVisibilityChanged(boolean visible) {
397 // When the on-screen setting is not displayed, we show the gripper.
398 // When the on-screen setting is displayed, we hide the gripper.
Cheng-Ru Lin2a79ecb2009-09-28 12:34:33 +0800399 int reverseVisibility = visible ? View.INVISIBLE : View.VISIBLE;
400 findViewById(R.id.btn_gripper).setVisibility(reverseVisibility);
401 findViewById(R.id.indicator_bar).setVisibility(reverseVisibility);
402
Owen Lin32bfffa2009-09-19 19:50:42 +0800403 if (visible) {
404 mPreferences.registerOnSharedPreferenceChangeListener(this);
405 } else {
406 mPreferences.unregisterOnSharedPreferenceChangeListener(this);
407 }
Owen Linc1f2e302009-09-14 19:04:37 +0800408 }
409
Wu-cheng Li35bda2d2009-09-27 20:45:42 -0700410 private boolean isZooming() {
411 mParameters = mCameraDevice.getParameters();
412 return "continuous".equals(mParameters.get(PARM_ZOOM_STATE));
413 }
414
415 private void zoomToLevel(String type, double zoomValue) {
416 if (zoomValue > mZoomMax) zoomValue = mZoomMax;
417 if (zoomValue < ZOOM_MIN) zoomValue = ZOOM_MIN;
418
419 // If the application sets a unchanged zoom value, the driver will stuck
420 // at the zoom state. This is a work-around to ensure the state is at
421 // "stop".
422 mParameters.set(PARM_ZOOM_STATE, ZOOM_STOP);
423 mCameraDevice.setParameters(mParameters);
424
425 mParameters.set(PARM_ZOOM_TO_LEVEL, Double.toString(zoomValue));
426 mParameters.set(PARM_ZOOM_STATE, type);
427 mCameraDevice.setParameters(mParameters);
428
429 if (ZOOM_IMMEDIATE.equals(type)) mZoomValue = zoomValue;
430 }
431
432 private void updateZoomButtonsEnabled() {
433 mZoomButtons.setZoomInEnabled(mZoomValue < mZoomMax);
434 mZoomButtons.setZoomOutEnabled(mZoomValue > ZOOM_MIN);
435 }
436
437 private class ZoomGestureListener extends
438 GestureDetector.SimpleOnGestureListener {
439 @Override
440 public boolean onDown(MotionEvent e) {
441 // Show zoom buttons only when preview is started and snapshot
442 // is not in progress. mZoomButtons may be null if it is not
443 // initialized.
444 if (!mPausing && isCameraIdle() && mPreviewing
445 && mZoomButtons != null) {
446 mZoomButtons.setVisible(true);
447 }
448 return true;
449 }
450
451 @Override
452 public boolean onDoubleTap(MotionEvent e) {
453 // Perform zoom only when preview is started and snapshot is not in
454 // progress.
455 if (mPausing || !isCameraIdle() || !mPreviewing
456 || mZoomButtons == null || isZooming()) {
457 return false;
458 }
459
460 if (mZoomValue < mZoomMax) {
461 // Zoom in to the maximum.
462 while (mZoomValue < mZoomMax) {
463 zoomToLevel(ZOOM_IMMEDIATE, mZoomValue + ZOOM_STEP_MIN);
464 // Wait for a while so we are not changing zoom too fast.
465 try {
466 Thread.sleep(5);
467 } catch (InterruptedException ex) {
468 }
469 }
470 } else {
471 // Zoom out to the minimum.
472 while (mZoomValue > ZOOM_MIN) {
473 zoomToLevel(ZOOM_IMMEDIATE, mZoomValue - ZOOM_STEP_MIN);
474 // Wait for a while so we are not changing zoom too fast.
475 try {
476 Thread.sleep(5);
477 } catch (InterruptedException ex) {
478 }
479 }
480 }
481 updateZoomButtonsEnabled();
482 return true;
483 }
484 }
485
Wu-cheng Liaa3cc202009-09-03 16:28:22 +0800486 @Override
487 public boolean dispatchTouchEvent(MotionEvent m) {
488 if (!super.dispatchTouchEvent(m) && mGestureDetector != null) {
489 return mGestureDetector.onTouchEvent(m);
490 }
491 return true;
492 }
493
Wu-cheng Li91227ec2009-08-31 19:31:59 +0800494 LocationListener [] mLocationListeners = new LocationListener[] {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800495 new LocationListener(LocationManager.GPS_PROVIDER),
496 new LocationListener(LocationManager.NETWORK_PROVIDER)
497 };
498
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800499 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
500 @Override
501 public void onReceive(Context context, Intent intent) {
502 String action = intent.getAction();
Wu-cheng Li1e509682009-07-29 16:08:17 +0800503 if (action.equals(Intent.ACTION_MEDIA_MOUNTED)
504 || action.equals(Intent.ACTION_MEDIA_UNMOUNTED)
505 || action.equals(Intent.ACTION_MEDIA_CHECKING)
506 || action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
507 checkStorage();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800508 } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
Wu-cheng Li1e509682009-07-29 16:08:17 +0800509 checkStorage();
Wu-cheng Lid12ae202009-07-27 17:44:56 +0800510 if (!mIsImageCaptureIntent) {
511 updateThumbnailButton();
512 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800513 }
514 }
515 };
516
Owen Lin0e841fe2009-04-09 07:41:20 -0700517 private class LocationListener
518 implements android.location.LocationListener {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800519 Location mLastLocation;
520 boolean mValid = false;
521 String mProvider;
522
523 public LocationListener(String provider) {
524 mProvider = provider;
525 mLastLocation = new Location(mProvider);
526 }
527
528 public void onLocationChanged(Location newLocation) {
Owen Lin0e841fe2009-04-09 07:41:20 -0700529 if (newLocation.getLatitude() == 0.0
530 && newLocation.getLongitude() == 0.0) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800531 // Hack to filter out 0.0,0.0 locations
532 return;
533 }
Owen Lin07c90562009-03-24 19:38:57 -0700534 // If GPS is available before start camera, we won't get status
535 // update so update GPS indicator when we receive data.
536 if (mRecordLocation
537 && LocationManager.GPS_PROVIDER.equals(mProvider)) {
Owen Lin37acf792009-09-17 17:55:37 +0800538 mGpsIndicator.setMode(GPS_MODE_ON);
Owen Lin07c90562009-03-24 19:38:57 -0700539 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800540 mLastLocation.set(newLocation);
541 mValid = true;
542 }
543
544 public void onProviderEnabled(String provider) {
545 }
546
547 public void onProviderDisabled(String provider) {
548 mValid = false;
549 }
550
Owen Lin0e841fe2009-04-09 07:41:20 -0700551 public void onStatusChanged(
552 String provider, int status, Bundle extras) {
Owen Lin07c90562009-03-24 19:38:57 -0700553 switch(status) {
554 case LocationProvider.OUT_OF_SERVICE:
555 case LocationProvider.TEMPORARILY_UNAVAILABLE: {
556 mValid = false;
557 if (mRecordLocation &&
558 LocationManager.GPS_PROVIDER.equals(provider)) {
Owen Lin37acf792009-09-17 17:55:37 +0800559 mGpsIndicator.setMode(GPS_MODE_OFF);
Owen Lin07c90562009-03-24 19:38:57 -0700560 }
561 break;
562 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800563 }
564 }
565
566 public Location current() {
567 return mValid ? mLastLocation : null;
568 }
Owen Lin937fc482009-04-14 02:02:51 -0700569 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800570
Wu-cheng Libcd13fa2009-04-20 18:12:41 +0800571 private final class OneShotPreviewCallback
572 implements android.hardware.Camera.PreviewCallback {
573 public void onPreviewFrame(byte[] data,
574 android.hardware.Camera camera) {
575 long now = System.currentTimeMillis();
576 if (mJpegPictureCallbackTime != 0) {
Yu Shan Emily Lau11cac262009-06-02 21:59:58 -0700577 mJpegPictureCallbackTimeLag = now - mJpegPictureCallbackTime;
578 Log.v(TAG, "mJpegPictureCallbackTimeLag = "
579 + mJpegPictureCallbackTimeLag + "ms");
Wu-cheng Libcd13fa2009-04-20 18:12:41 +0800580 mJpegPictureCallbackTime = 0;
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800581 } else {
582 Log.v(TAG, "Got first frame");
Wu-cheng Libcd13fa2009-04-20 18:12:41 +0800583 }
584 }
585 }
586
Owen Lin0e841fe2009-04-09 07:41:20 -0700587 private final class ShutterCallback
588 implements android.hardware.Camera.ShutterCallback {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800589 public void onShutter() {
Wu-cheng Libcd13fa2009-04-20 18:12:41 +0800590 mShutterCallbackTime = System.currentTimeMillis();
Yu Shan Emily Lau11cac262009-06-02 21:59:58 -0700591 mShutterLag = mShutterCallbackTime - mCaptureStartTime;
592 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
Chih-Chung Chang75ae09f2009-04-23 17:20:42 +0800593 clearFocusState();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800594 }
Owen Lin937fc482009-04-14 02:02:51 -0700595 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800596
597 private final class RawPictureCallback implements PictureCallback {
Owen Lin0e841fe2009-04-09 07:41:20 -0700598 public void onPictureTaken(
599 byte [] rawData, android.hardware.Camera camera) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800600 mRawPictureCallbackTime = System.currentTimeMillis();
Yu Shan Emily Lau11cac262009-06-02 21:59:58 -0700601 mShutterAndRawPictureCallbackTime =
602 mRawPictureCallbackTime - mShutterCallbackTime;
603 Log.v(TAG, "mShutterAndRawPictureCallbackTime = "
604 + mShutterAndRawPictureCallbackTime + "ms");
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800605 }
Owen Lin937fc482009-04-14 02:02:51 -0700606 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800607
608 private final class JpegPictureCallback implements PictureCallback {
609 Location mLocation;
610
611 public JpegPictureCallback(Location loc) {
612 mLocation = loc;
613 }
614
Owen Lin0e841fe2009-04-09 07:41:20 -0700615 public void onPictureTaken(
repo sync6c281192009-06-06 11:18:07 +0800616 final byte [] jpegData, final android.hardware.Camera camera) {
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700617 if (mPausing) {
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700618 return;
619 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800620
Wu-cheng Libcd13fa2009-04-20 18:12:41 +0800621 mJpegPictureCallbackTime = System.currentTimeMillis();
Yu Shan Emily Lau11cac262009-06-02 21:59:58 -0700622 mRawPictureAndJpegPictureCallbackTime =
623 mJpegPictureCallbackTime - mRawPictureCallbackTime;
624 Log.v(TAG, "mRawPictureAndJpegPictureCallbackTime = "
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800625 + mRawPictureAndJpegPictureCallbackTime + "ms");
repo sync2bb9e742009-06-24 11:42:53 +0800626 mImageCapture.storeImage(jpegData, camera, mLocation);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800627
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +0800628 if (!mIsImageCaptureIntent) {
repo sync2bb9e742009-06-24 11:42:53 +0800629 long delay = 1200 - (
Owen Lin0e841fe2009-04-09 07:41:20 -0700630 System.currentTimeMillis() - mRawPictureCallbackTime);
631 mHandler.sendEmptyMessageDelayed(
632 RESTART_PREVIEW, Math.max(delay, 0));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800633 }
634 }
Owen Lin937fc482009-04-14 02:02:51 -0700635 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800636
Owen Lin0e841fe2009-04-09 07:41:20 -0700637 private final class AutoFocusCallback
638 implements android.hardware.Camera.AutoFocusCallback {
639 public void onAutoFocus(
640 boolean focused, android.hardware.Camera camera) {
Wu-cheng Libcd13fa2009-04-20 18:12:41 +0800641 mFocusCallbackTime = System.currentTimeMillis();
Yu Shan Emily Lau11cac262009-06-02 21:59:58 -0700642 mAutoFocusTime = mFocusCallbackTime - mFocusStartTime;
643 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
Wu-cheng Li5fa94832009-06-15 22:45:17 +0800644 if (mFocusState == FOCUSING_SNAP_ON_FINISH) {
Owen Lin0e841fe2009-04-09 07:41:20 -0700645 // Take the picture no matter focus succeeds or fails. No need
646 // to play the AF sound if we're about to play the shutter
647 // sound.
Chih-Chung Chang75ae09f2009-04-23 17:20:42 +0800648 if (focused) {
649 mFocusState = FOCUS_SUCCESS;
650 } else {
651 mFocusState = FOCUS_FAIL;
652 }
repo sync6c281192009-06-06 11:18:07 +0800653 mImageCapture.onSnap();
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800654 } else if (mFocusState == FOCUSING) {
655 // User is half-pressing the focus key. Play the focus tone.
656 // Do not take the picture now.
657 ToneGenerator tg = mFocusToneGenerator;
Owen Lin0e841fe2009-04-09 07:41:20 -0700658 if (tg != null) {
659 tg.startTone(ToneGenerator.TONE_PROP_BEEP2);
660 }
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800661 if (focused) {
662 mFocusState = FOCUS_SUCCESS;
Owen Lin0e841fe2009-04-09 07:41:20 -0700663 } else {
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -0800664 mFocusState = FOCUS_FAIL;
665 }
666 } else if (mFocusState == FOCUS_NOT_STARTED) {
667 // User has released the focus key before focus completes.
668 // Do nothing.
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700669 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800670 updateFocusIndicator();
671 }
Owen Lin937fc482009-04-14 02:02:51 -0700672 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800673
Yu Shan Emily Laucede87f2009-07-02 18:07:17 -0700674 private final class ErrorCallback
675 implements android.hardware.Camera.ErrorCallback {
Chih-Chung Chang9b93bcb2009-09-04 19:46:14 +0800676 public void onError(int error, android.hardware.Camera camera) {
Yu Shan Emily Laucede87f2009-07-02 18:07:17 -0700677 if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) {
678 mMediaServerDied = true;
679 Log.v(TAG, "media server died");
680 }
681 }
682 }
683
Wu-cheng Li35bda2d2009-09-27 20:45:42 -0700684 private final class ZoomCallback
Wu-cheng Lia5d6b702009-10-05 18:47:46 -0700685 implements android.hardware.Camera.ZoomCallback {
686 public void onZoomUpdate(int zoomLevel, boolean stopped,
687 android.hardware.Camera camera) {
Wu-cheng Li35bda2d2009-09-27 20:45:42 -0700688 mZoomValue = (double) zoomLevel / 1000;
Wu-cheng Lia5d6b702009-10-05 18:47:46 -0700689 Log.v(TAG, "ZoomCallback: zoom level=" + zoomLevel + ".stopped="
690 + stopped);
Wu-cheng Li35bda2d2009-09-27 20:45:42 -0700691 updateZoomButtonsEnabled();
692 }
693 }
694
Chih-Chung Chang7b645fb2009-08-31 11:14:15 +0800695 private class ImageCapture {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800696
697 private boolean mCancel = false;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800698
699 private Uri mLastContentUri;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800700
Chih-Chung Changc30e5c22009-09-23 16:02:30 -0700701 byte[] mCaptureOnlyData;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800702
Chih-Chung Chang0b706b82009-09-22 11:52:54 -0700703 // Returns the rotation degree in the jpeg header.
704 private int storeImage(byte[] data, Location loc) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800705 try {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800706 long dateTaken = System.currentTimeMillis();
707 String name = createName(dateTaken) + ".jpg";
Chih-Chung Chang140229c2009-09-28 10:47:18 -0700708 int[] degree = new int[1];
Chih-Chung Chang58e94ed2009-04-17 11:02:01 +0800709 mLastContentUri = ImageManager.addImage(
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800710 mContentResolver,
711 name,
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800712 dateTaken,
Chih-Chung Chang140229c2009-09-28 10:47:18 -0700713 loc, // location from gps/network
714 ImageManager.CAMERA_IMAGE_BUCKET_NAME, name,
715 null, data,
716 degree);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800717 if (mLastContentUri == null) {
718 // this means we got an error
719 mCancel = true;
720 }
721 if (!mCancel) {
Chih-Chung Chang58e94ed2009-04-17 11:02:01 +0800722 ImageManager.setImageSize(mContentResolver, mLastContentUri,
Owen Lin4689e592009-04-15 14:42:39 +0800723 new File(ImageManager.CAMERA_IMAGE_BUCKET_NAME,
724 name).length());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800725 }
Chih-Chung Chang140229c2009-09-28 10:47:18 -0700726 return degree[0];
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800727 } catch (Exception ex) {
728 Log.e(TAG, "Exception while compressing image.", ex);
Chih-Chung Chang0b706b82009-09-22 11:52:54 -0700729 return 0;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800730 }
731 }
732
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800733 public void storeImage(final byte[] data,
734 android.hardware.Camera camera, Location loc) {
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +0800735 if (!mIsImageCaptureIntent) {
Chih-Chung Chang0b706b82009-09-22 11:52:54 -0700736 int degree = storeImage(data, loc);
Owen Lin0e841fe2009-04-09 07:41:20 -0700737 sendBroadcast(new Intent(
738 "com.android.camera.NEW_PICTURE", mLastContentUri));
Chih-Chung Chang0b706b82009-09-22 11:52:54 -0700739 setLastPictureThumb(data, degree,
740 mImageCapture.getLastCaptureUri());
repo sync2bb9e742009-06-24 11:42:53 +0800741 mThumbController.updateDisplayIfNeeded();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800742 } else {
Chih-Chung Changc30e5c22009-09-23 16:02:30 -0700743 mCaptureOnlyData = data;
repo sync2bb9e742009-06-24 11:42:53 +0800744 showPostCaptureAlert();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800745 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800746 }
747
Owen Lin0e841fe2009-04-09 07:41:20 -0700748 /**
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800749 * Initiate the capture of an image.
750 */
Wu-cheng Lid16a0612009-05-13 16:49:00 +0800751 public void initiate() {
Dave Sparks11c53782009-03-24 22:20:14 -0700752 if (mCameraDevice == null) {
753 return;
754 }
755
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800756 mCancel = false;
Dave Sparks11c53782009-03-24 22:20:14 -0700757
Wu-cheng Lid16a0612009-05-13 16:49:00 +0800758 capture();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800759 }
760
761 public Uri getLastCaptureUri() {
762 return mLastContentUri;
763 }
764
Chih-Chung Changc30e5c22009-09-23 16:02:30 -0700765 public byte[] getLastCaptureData() {
766 return mCaptureOnlyData;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800767 }
768
Wu-cheng Lid16a0612009-05-13 16:49:00 +0800769 private void capture() {
Chih-Chung Changc30e5c22009-09-23 16:02:30 -0700770 mCaptureOnlyData = null;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800771
Wu-cheng Li4305c702009-09-02 16:33:59 +0800772 // Set rotation.
Chih-Chung Chang98334d22009-05-27 12:27:02 +0800773 int orientation = mLastOrientation;
774 if (orientation != OrientationEventListener.ORIENTATION_UNKNOWN) {
775 orientation += 90;
776 }
777 orientation = ImageManager.roundOrientation(orientation);
778 Log.v(TAG, "mLastOrientation = " + mLastOrientation
779 + ", orientation = " + orientation);
Wu-cheng Li4305c702009-09-02 16:33:59 +0800780 mParameters.setRotation(orientation);
Chih-Chung Chang98334d22009-05-27 12:27:02 +0800781
Wu-cheng Li4305c702009-09-02 16:33:59 +0800782 // Clear previous GPS location from the parameters.
783 mParameters.removeGpsData();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800784
Wu-cheng Li4305c702009-09-02 16:33:59 +0800785 // Set GPS location.
Owen Lin07c90562009-03-24 19:38:57 -0700786 Location loc = mRecordLocation ? getCurrentLocation() : null;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800787 if (loc != null) {
788 double lat = loc.getLatitude();
789 double lon = loc.getLongitude();
790 boolean hasLatLon = (lat != 0.0d) || (lon != 0.0d);
791
792 if (hasLatLon) {
Wu-cheng Li4305c702009-09-02 16:33:59 +0800793 mParameters.setGpsLatitude(lat);
794 mParameters.setGpsLongitude(lon);
The Android Open Source Projectd7e9d192009-03-05 20:00:44 -0800795 if (loc.hasAltitude()) {
Wu-cheng Li4305c702009-09-02 16:33:59 +0800796 mParameters.setGpsAltitude(loc.getAltitude());
The Android Open Source Projectd7e9d192009-03-05 20:00:44 -0800797 } else {
798 // for NETWORK_PROVIDER location provider, we may have
799 // no altitude information, but the driver needs it, so
800 // we fake one.
Wu-cheng Li4305c702009-09-02 16:33:59 +0800801 mParameters.setGpsAltitude(0);
The Android Open Source Projectd7e9d192009-03-05 20:00:44 -0800802 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800803 if (loc.getTime() != 0) {
804 // Location.getTime() is UTC in milliseconds.
805 // gps-timestamp is UTC in seconds.
806 long utcTimeSeconds = loc.getTime() / 1000;
Wu-cheng Li4305c702009-09-02 16:33:59 +0800807 mParameters.setGpsTimestamp(utcTimeSeconds);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800808 }
809 } else {
810 loc = null;
811 }
812 }
813
814 mCameraDevice.setParameters(mParameters);
815
Owen Lin0e841fe2009-04-09 07:41:20 -0700816 mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback,
817 new JpegPictureCallback(loc));
Wu-cheng Li5fa94832009-06-15 22:45:17 +0800818 mPreviewing = false;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800819 }
820
821 public void onSnap() {
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +0800822 // If we are already in the middle of taking a snapshot then ignore.
823 if (mPausing || mStatus == SNAPSHOT_IN_PROGRESS) {
The Android Open Source Projecte3f45162009-03-11 12:11:58 -0700824 return;
825 }
Wu-cheng Libcd13fa2009-04-20 18:12:41 +0800826 mCaptureStartTime = System.currentTimeMillis();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800827
Owen Lin0e841fe2009-04-09 07:41:20 -0700828 // Don't check the filesystem here, we can't afford the latency.
829 // Instead, check the cached value which was calculated when the
830 // preview was restarted.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800831 if (mPicturesRemaining < 1) {
832 updateStorageHint(mPicturesRemaining);
833 return;
834 }
835
836 mStatus = SNAPSHOT_IN_PROGRESS;
837
Wu-cheng Lid16a0612009-05-13 16:49:00 +0800838 mImageCapture.initiate();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800839 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -0700840
Chih-Chung Changc30e5c22009-09-23 16:02:30 -0700841 private void clearLastData() {
842 mCaptureOnlyData = null;
The Android Open Source Project9a379bd2009-03-09 11:52:14 -0700843 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800844 }
845
Chih-Chung Changcd972b02009-09-22 16:47:43 -0700846 public boolean saveDataToFile(String filePath, byte[] data) {
847 FileOutputStream f = null;
848 try {
849 f = new FileOutputStream(filePath);
850 f.write(data);
851 } catch (IOException e) {
852 return false;
853 } finally {
854 MenuHelper.closeSilently(f);
855 }
856 return true;
857 }
858
Chih-Chung Chang0b706b82009-09-22 11:52:54 -0700859 private void setLastPictureThumb(byte[] data, int degree, Uri uri) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800860 BitmapFactory.Options options = new BitmapFactory.Options();
861 options.inSampleSize = 16;
Owen Lin0e841fe2009-04-09 07:41:20 -0700862 Bitmap lastPictureThumb =
863 BitmapFactory.decodeByteArray(data, 0, data.length, options);
Chih-Chung Chang0b706b82009-09-22 11:52:54 -0700864 lastPictureThumb = Util.rotate(lastPictureThumb, degree);
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700865 mThumbController.setData(uri, lastPictureThumb);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800866 }
867
Owen Lin0e841fe2009-04-09 07:41:20 -0700868 private static String createName(long dateTaken) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800869 return DateFormat.format("yyyy-MM-dd kk.mm.ss", dateTaken).toString();
870 }
871
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800872 @Override
873 public void onCreate(Bundle icicle) {
874 super.onCreate(icicle);
875
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800876 Window win = getWindow();
877 win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
878 setContentView(R.layout.camera);
Cheng-Ru Linffcca742009-09-28 03:21:25 +0800879 mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview);
880
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800881 mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
882
883 /*
884 * To reduce startup time, we start the preview in another thread.
885 * We make sure the preview is started at the end of onCreate.
886 */
887 Thread startPreviewThread = new Thread(new Runnable() {
888 public void run() {
Owen Lin3f3c8572009-08-18 13:33:49 +0800889 try {
890 mStartPreviewFail = false;
891 startPreview();
892 } catch (CameraHardwareException e) {
Owen Linf6ef7b92009-09-14 18:48:12 +0800893 // In eng build, we throw the exception so that test tool
894 // can detect it and report it
895 if ("eng".equals(Build.TYPE)) {
896 throw new RuntimeException(e);
897 }
Owen Lin3f3c8572009-08-18 13:33:49 +0800898 mStartPreviewFail = true;
899 }
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800900 }
901 });
902 startPreviewThread.start();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800903
904 // don't set mSurfaceHolder here. We have it set ONLY within
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +0800905 // surfaceChanged / surfaceDestroyed, other parts of the code
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800906 // assume that when it is set, the surface is also set.
907 SurfaceHolder holder = mSurfaceView.getHolder();
908 holder.addCallback(this);
909 holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
910
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700911 mIsImageCaptureIntent = isImageCaptureIntent();
Chih-Chung Changcd972b02009-09-22 16:47:43 -0700912 if (mIsImageCaptureIntent) {
913 setupCaptureParams();
914 }
915
Owen Lin61b98312009-06-19 00:21:10 -0700916 LayoutInflater inflater = getLayoutInflater();
917
Chih-Chung Chang91acfc92009-07-06 15:37:24 +0800918 ViewGroup rootView = (ViewGroup) findViewById(R.id.camera);
Wu-cheng Li84f96462009-06-19 20:11:44 +0800919 if (mIsImageCaptureIntent) {
Owen Lin61b98312009-06-19 00:21:10 -0700920 View controlBar = inflater.inflate(
921 R.layout.attach_camera_control, rootView);
922 controlBar.findViewById(R.id.btn_cancel).setOnClickListener(this);
923 controlBar.findViewById(R.id.btn_retake).setOnClickListener(this);
924 controlBar.findViewById(R.id.btn_done).setOnClickListener(this);
925 } else {
926 inflater.inflate(R.layout.camera_control, rootView);
Owen Lin2e768c12009-07-01 15:51:45 -0700927 mSwitcher = ((Switcher) findViewById(R.id.camera_switch));
928 mSwitcher.setOnSwitchListener(this);
Chih-Chung Chang781f55b2009-08-10 17:00:52 +0800929 mSwitcher.addTouchView(findViewById(R.id.camera_switch_set));
Wu-cheng Li84f96462009-06-19 20:11:44 +0800930 }
Owen Linc1f2e302009-09-14 19:04:37 +0800931 findViewById(R.id.btn_gripper)
932 .setOnTouchListener(new GripperTouchListener());
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -0700933
Owen Lin37acf792009-09-17 17:55:37 +0800934 mFlashIndicator = (IconIndicator) findViewById(R.id.flash_icon);
Cheng-Ru Lin27e69922009-09-30 13:48:59 +0800935 mFocusIndicator = (IconIndicator) findViewById(R.id.focus_icon);
Cheng-Ru Lin25156f02009-10-01 00:34:41 +0800936 mSceneModeIndicator = (IconIndicator) findViewById(R.id.scenemode_icon);
Cheng-Ru Lin27e69922009-09-30 13:48:59 +0800937 mWhitebalanceIndicator =
938 (IconIndicator) findViewById(R.id.whitebalance_icon);
Owen Lin37acf792009-09-17 17:55:37 +0800939
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800940 // Make sure preview is started.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800941 try {
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +0800942 startPreviewThread.join();
Owen Linf6ef7b92009-09-14 18:48:12 +0800943 if (mStartPreviewFail) {
944 showCameraErrorAndFinish();
945 return;
946 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800947 } catch (InterruptedException ex) {
Owen Lin0e841fe2009-04-09 07:41:20 -0700948 // ignore
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800949 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800950 }
951
Owen Linc1f2e302009-09-14 19:04:37 +0800952 private class GripperTouchListener implements View.OnTouchListener {
953 public boolean onTouch(View view, MotionEvent event) {
954 switch (event.getAction()) {
955 case MotionEvent.ACTION_DOWN:
956 return true;
957 case MotionEvent.ACTION_UP:
958 showOnScreenSettings();
959 return true;
960 }
961 return false;
962 }
963 }
964
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800965 @Override
966 public void onStart() {
967 super.onStart();
Owen Lin2e768c12009-07-01 15:51:45 -0700968 if (!mIsImageCaptureIntent) {
969 mSwitcher.setSwitch(SWITCH_CAMERA);
970 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -0800971 }
972
Wu-cheng Lid12ae202009-07-27 17:44:56 +0800973 private void checkStorage() {
Wu-cheng Lid12ae202009-07-27 17:44:56 +0800974 if (ImageManager.isMediaScannerScanning(getContentResolver())) {
975 mPicturesRemaining = MenuHelper.NO_STORAGE_ERROR;
Wu-cheng Li1e509682009-07-29 16:08:17 +0800976 } else {
977 calculatePicturesRemaining();
Wu-cheng Lid12ae202009-07-27 17:44:56 +0800978 }
Wu-cheng Li1e509682009-07-29 16:08:17 +0800979 updateStorageHint(mPicturesRemaining);
980 }
Wu-cheng Lid12ae202009-07-27 17:44:56 +0800981
Cheng-Ru Lin301c0882009-10-01 05:51:22 +0800982
Owen Linc1f2e302009-09-14 19:04:37 +0800983 private void showOnScreenSettings() {
984 if (mSettings == null) {
985 mSettings = new OnScreenSettings(
986 findViewById(R.id.camera_preview));
Cheng-Ru Lindf3731b2009-10-02 08:37:21 +0800987 CameraSettings helper =
988 new CameraSettings(this, mInitialParameters);
Owen Linc1f2e302009-09-14 19:04:37 +0800989 mSettings.setPreferenceScreen(helper
990 .getPreferenceScreen(R.xml.camera_preferences));
991 mSettings.setOnVisibilityChangedListener(this);
Cheng-Ru Lin301c0882009-10-01 05:51:22 +0800992
Cheng-Ru Lin3b90cce2009-10-01 11:42:29 +0800993 String sceneMode = mParameters.getSceneMode();
Cheng-Ru Lindf3731b2009-10-02 08:37:21 +0800994 if (sceneMode == null
995 || Parameters.SCENE_MODE_AUTO.equals(sceneMode)) {
Cheng-Ru Lin3b90cce2009-10-01 11:42:29 +0800996 // If scene mode is auto, cancel override in settings
Cheng-Ru Lin301c0882009-10-01 05:51:22 +0800997 mSettings.overrideSettings(CameraSettings.KEY_FLASH_MODE, null);
998 mSettings.overrideSettings(CameraSettings.KEY_FOCUS_MODE, null);
999 mSettings.overrideSettings(
1000 CameraSettings.KEY_WHITE_BALANCE, null);
1001 } else {
Cheng-Ru Lin3b90cce2009-10-01 11:42:29 +08001002 // If scene mode is not auto, override the value in settings
Cheng-Ru Lin301c0882009-10-01 05:51:22 +08001003 mSettings.overrideSettings(CameraSettings.KEY_FLASH_MODE,
1004 mParameters.getFlashMode());
1005 mSettings.overrideSettings(CameraSettings.KEY_FOCUS_MODE,
1006 mParameters.getFocusMode());
1007 mSettings.overrideSettings(CameraSettings.KEY_WHITE_BALANCE,
1008 mParameters.getWhiteBalance());
1009 }
Owen Linc1f2e302009-09-14 19:04:37 +08001010 }
Cheng-Ru Lin301c0882009-10-01 05:51:22 +08001011
Cheng-Ru Linabdd8a12009-09-30 15:35:43 +08001012 mSettings.setVisible(true);
Owen Linc1f2e302009-09-14 19:04:37 +08001013 }
1014
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001015 public void onClick(View v) {
1016 switch (v.getId()) {
Owen Lin61b98312009-06-19 00:21:10 -07001017 case R.id.btn_retake:
1018 hidePostCaptureAlert();
1019 restartPreview();
1020 break;
Owen Lindad4b182009-06-11 16:02:29 -07001021 case R.id.review_thumbnail:
Wu-cheng Li5fa94832009-06-15 22:45:17 +08001022 if (isCameraIdle()) {
Owen Lin059daa32009-05-18 15:31:17 -07001023 viewLastImage();
1024 }
1025 break;
Owen Lin61b98312009-06-19 00:21:10 -07001026 case R.id.btn_done:
Owen Lin059daa32009-05-18 15:31:17 -07001027 doAttach();
1028 break;
Owen Lin61b98312009-06-19 00:21:10 -07001029 case R.id.btn_cancel:
Owen Lin059daa32009-05-18 15:31:17 -07001030 doCancel();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001031 }
1032 }
1033
Chih-Chung Changc30e5c22009-09-23 16:02:30 -07001034 private Bitmap createCaptureBitmap(byte[] data) {
1035 // This is really stupid...we just want to read the orientation in
1036 // the jpeg header.
1037 String filepath = ImageManager.getTempJpegPath();
1038 int degree = 0;
1039 if (saveDataToFile(filepath, data)) {
1040 degree = ImageManager.getExifOrientation(filepath);
1041 new File(filepath).delete();
1042 }
1043
1044 // Limit to 50k pixels so we can return it in the intent.
1045 Bitmap bitmap = Util.makeBitmap(data, 50*1024);
1046 bitmap = Util.rotate(bitmap, degree);
1047 return bitmap;
1048 }
1049
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001050 private void doAttach() {
The Android Open Source Projectde365d82009-03-18 17:39:48 -07001051 if (mPausing) {
The Android Open Source Projecte3f45162009-03-11 12:11:58 -07001052 return;
1053 }
Chih-Chung Changc30e5c22009-09-23 16:02:30 -07001054
1055 byte[] data = mImageCapture.getLastCaptureData();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001056
Chih-Chung Changcd972b02009-09-22 16:47:43 -07001057 if (mCropValue == null) {
Owen Lin0e841fe2009-04-09 07:41:20 -07001058 // First handle the no crop case -- just return the value. If the
1059 // caller specifies a "save uri" then write the data to it's
1060 // stream. Otherwise, pass back a scaled down version of the bitmap
1061 // directly in the extras.
Chih-Chung Changcd972b02009-09-22 16:47:43 -07001062 if (mSaveUri != null) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001063 OutputStream outputStream = null;
1064 try {
Chih-Chung Changcd972b02009-09-22 16:47:43 -07001065 outputStream = mContentResolver.openOutputStream(mSaveUri);
Chih-Chung Changc30e5c22009-09-23 16:02:30 -07001066 outputStream.write(data);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001067 outputStream.close();
1068
1069 setResult(RESULT_OK);
1070 finish();
1071 } catch (IOException ex) {
Owen Lin0e841fe2009-04-09 07:41:20 -07001072 // ignore exception
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001073 } finally {
Chih-Chung Changc30e5c22009-09-23 16:02:30 -07001074 Util.closeSilently(outputStream);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001075 }
1076 } else {
Chih-Chung Changc30e5c22009-09-23 16:02:30 -07001077 Bitmap bitmap = createCaptureBitmap(data);
Owen Lin0e841fe2009-04-09 07:41:20 -07001078 setResult(RESULT_OK,
1079 new Intent("inline-data").putExtra("data", bitmap));
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001080 finish();
1081 }
Owen Lin0e841fe2009-04-09 07:41:20 -07001082 } else {
1083 // Save the image to a temp file and invoke the cropper
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001084 Uri tempUri = null;
1085 FileOutputStream tempStream = null;
1086 try {
1087 File path = getFileStreamPath(sTempCropFilename);
1088 path.delete();
1089 tempStream = openFileOutput(sTempCropFilename, 0);
Chih-Chung Changc30e5c22009-09-23 16:02:30 -07001090 tempStream.write(data);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001091 tempStream.close();
1092 tempUri = Uri.fromFile(path);
1093 } catch (FileNotFoundException ex) {
1094 setResult(Activity.RESULT_CANCELED);
1095 finish();
1096 return;
1097 } catch (IOException ex) {
1098 setResult(Activity.RESULT_CANCELED);
1099 finish();
1100 return;
1101 } finally {
Chih-Chung Changc30e5c22009-09-23 16:02:30 -07001102 Util.closeSilently(tempStream);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001103 }
1104
1105 Bundle newExtras = new Bundle();
Chih-Chung Changcd972b02009-09-22 16:47:43 -07001106 if (mCropValue.equals("circle")) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001107 newExtras.putString("circleCrop", "true");
Owen Lin0e841fe2009-04-09 07:41:20 -07001108 }
Chih-Chung Changcd972b02009-09-22 16:47:43 -07001109 if (mSaveUri != null) {
1110 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
Owen Lin0e841fe2009-04-09 07:41:20 -07001111 } else {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001112 newExtras.putBoolean("return-data", true);
Owen Lin0e841fe2009-04-09 07:41:20 -07001113 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001114
1115 Intent cropIntent = new Intent();
Owen Linc1f2e302009-09-14 19:04:37 +08001116 cropIntent.setClass(this, CropImage.class);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001117 cropIntent.setData(tempUri);
1118 cropIntent.putExtras(newExtras);
1119
1120 startActivityForResult(cropIntent, CROP_MSG);
1121 }
1122 }
1123
1124 private void doCancel() {
1125 setResult(RESULT_CANCELED, new Intent());
1126 finish();
1127 }
1128
1129 public void onShutterButtonFocus(ShutterButton button, boolean pressed) {
Dave Sparks11c53782009-03-24 22:20:14 -07001130 if (mPausing) {
The Android Open Source Projecte3f45162009-03-11 12:11:58 -07001131 return;
1132 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001133 switch (button.getId()) {
Owen Lindad4b182009-06-11 16:02:29 -07001134 case R.id.shutter_button:
repo sync2bb9e742009-06-24 11:42:53 +08001135 doFocus(pressed);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001136 break;
1137 }
1138 }
1139
1140 public void onShutterButtonClick(ShutterButton button) {
Dave Sparks11c53782009-03-24 22:20:14 -07001141 if (mPausing) {
The Android Open Source Projecte3f45162009-03-11 12:11:58 -07001142 return;
1143 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001144 switch (button.getId()) {
Owen Lindad4b182009-06-11 16:02:29 -07001145 case R.id.shutter_button:
repo sync2bb9e742009-06-24 11:42:53 +08001146 doSnap();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001147 break;
1148 }
1149 }
1150
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001151 private OnScreenHint mStorageHint;
1152
1153 private void updateStorageHint(int remaining) {
1154 String noStorageText = null;
1155
1156 if (remaining == MenuHelper.NO_STORAGE_ERROR) {
1157 String state = Environment.getExternalStorageState();
Wu-cheng Lid12ae202009-07-27 17:44:56 +08001158 if (state == Environment.MEDIA_CHECKING ||
1159 ImageManager.isMediaScannerScanning(getContentResolver())) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001160 noStorageText = getString(R.string.preparing_sd);
1161 } else {
1162 noStorageText = getString(R.string.no_storage);
1163 }
1164 } else if (remaining < 1) {
1165 noStorageText = getString(R.string.not_enough_space);
1166 }
1167
1168 if (noStorageText != null) {
1169 if (mStorageHint == null) {
1170 mStorageHint = OnScreenHint.makeText(this, noStorageText);
1171 } else {
1172 mStorageHint.setText(noStorageText);
1173 }
1174 mStorageHint.show();
1175 } else if (mStorageHint != null) {
1176 mStorageHint.cancel();
1177 mStorageHint = null;
1178 }
1179 }
1180
Chih-Chung Chang522e8362009-08-26 16:12:34 +08001181 private void installIntentFilter() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001182 // install an intent filter to receive SD card related events.
Owen Lin0e841fe2009-04-09 07:41:20 -07001183 IntentFilter intentFilter =
1184 new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001185 intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
1186 intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
1187 intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
1188 intentFilter.addAction(Intent.ACTION_MEDIA_CHECKING);
1189 intentFilter.addDataScheme("file");
1190 registerReceiver(mReceiver, intentFilter);
1191 mDidRegister = true;
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001192 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001193
Chih-Chung Chang522e8362009-08-26 16:12:34 +08001194 private void initializeFocusTone() {
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001195 // Initialize focus tone generator.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001196 try {
Owen Lin0e841fe2009-04-09 07:41:20 -07001197 mFocusToneGenerator = new ToneGenerator(
1198 AudioManager.STREAM_SYSTEM, FOCUS_BEEP_VOLUME);
Wu-cheng Lifa1dfa22009-06-10 14:44:43 +08001199 } catch (Throwable ex) {
1200 Log.w(TAG, "Exception caught while creating tone generator: ", ex);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001201 mFocusToneGenerator = null;
1202 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001203 }
1204
Chih-Chung Chang522e8362009-08-26 16:12:34 +08001205 private void readPreference() {
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001206 mRecordLocation = mPreferences.getBoolean(
1207 "pref_camera_recordlocation_key", false);
1208 mFocusMode = mPreferences.getString(
1209 CameraSettings.KEY_FOCUS_MODE,
1210 getString(R.string.pref_camera_focusmode_default));
1211 }
1212
1213 @Override
1214 public void onResume() {
1215 super.onResume();
1216
1217 mPausing = false;
1218 mJpegPictureCallbackTime = 0;
1219 mImageCapture = new ImageCapture();
1220
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +08001221 // Start the preview if it is not started.
Owen Lin3f3c8572009-08-18 13:33:49 +08001222 if (!mPreviewing && !mStartPreviewFail) {
1223 try {
1224 startPreview();
1225 } catch (CameraHardwareException e) {
1226 showCameraErrorAndFinish();
1227 return;
1228 }
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +08001229 }
Wu-cheng Li785cd002009-07-10 17:38:43 +08001230
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +08001231 if (mSurfaceHolder != null) {
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +08001232 // If first time initialization is not finished, put it in the
1233 // message queue.
1234 if (!mFirstTimeInitialized) {
1235 mHandler.sendEmptyMessage(FIRST_TIME_INIT);
1236 } else {
1237 initializeSecondTime();
1238 }
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001239 }
Owen Lincc8d7562009-09-16 14:43:09 +08001240 keepScreenOnAwhile();
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001241 }
1242
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001243 private static ImageManager.DataLocation dataLocation() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001244 return ImageManager.DataLocation.EXTERNAL;
1245 }
1246
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001247 @Override
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001248 protected void onPause() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001249 mPausing = true;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001250 stopPreview();
Wu-cheng Li4904e972009-05-04 19:30:10 +08001251 // Close the camera now because other activities may need to use it.
1252 closeCamera();
Owen Lincc8d7562009-09-16 14:43:09 +08001253 resetScreenOn();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001254
Owen Lin2c6c6172009-09-01 14:51:53 +08001255 if (mSettings != null && mSettings.isVisible()) {
1256 mSettings.setVisible(false);
1257 }
1258
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001259 if (mFirstTimeInitialized) {
1260 mOrientationListener.disable();
Owen Lin37acf792009-09-17 17:55:37 +08001261 mGpsIndicator.setMode(GPS_MODE_OFF);
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001262 if (!mIsImageCaptureIntent) {
1263 mThumbController.storeData(
1264 ImageManager.getLastImageThumbPath());
1265 }
1266 hidePostCaptureAlert();
1267 }
1268
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001269 if (mDidRegister) {
1270 unregisterReceiver(mReceiver);
1271 mDidRegister = false;
1272 }
1273 stopReceivingLocationUpdates();
1274
1275 if (mFocusToneGenerator != null) {
1276 mFocusToneGenerator.release();
1277 mFocusToneGenerator = null;
1278 }
1279
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001280 if (mStorageHint != null) {
1281 mStorageHint.cancel();
1282 mStorageHint = null;
1283 }
The Android Open Source Projectde365d82009-03-18 17:39:48 -07001284
The Android Open Source Project9a379bd2009-03-09 11:52:14 -07001285 // If we are in an image capture intent and has taken
1286 // a picture, we just clear it in onPause.
Chih-Chung Changc30e5c22009-09-23 16:02:30 -07001287 mImageCapture.clearLastData();
The Android Open Source Project9a379bd2009-03-09 11:52:14 -07001288 mImageCapture = null;
The Android Open Source Projecte3f45162009-03-11 12:11:58 -07001289
Wu-cheng Li35bda2d2009-09-27 20:45:42 -07001290 // This is necessary to make the ZoomButtonsController unregister
1291 // its configuration change receiver.
1292 if (mZoomButtons != null) {
1293 mZoomButtons.setVisible(false);
1294 }
1295
Wu-cheng Lid16a0612009-05-13 16:49:00 +08001296 // Remove the messages in the event queue.
Wu-cheng Lid16a0612009-05-13 16:49:00 +08001297 mHandler.removeMessages(RESTART_PREVIEW);
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +08001298 mHandler.removeMessages(FIRST_TIME_INIT);
Wu-cheng Lid16a0612009-05-13 16:49:00 +08001299
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001300 super.onPause();
1301 }
1302
1303 @Override
Owen Lin0e841fe2009-04-09 07:41:20 -07001304 protected void onActivityResult(
1305 int requestCode, int resultCode, Intent data) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001306 switch (requestCode) {
1307 case CROP_MSG: {
1308 Intent intent = new Intent();
1309 if (data != null) {
1310 Bundle extras = data.getExtras();
1311 if (extras != null) {
1312 intent.putExtras(extras);
1313 }
1314 }
1315 setResult(resultCode, intent);
1316 finish();
1317
1318 File path = getFileStreamPath(sTempCropFilename);
1319 path.delete();
1320
1321 break;
1322 }
1323 }
1324 }
1325
repo syn && make -j4fcb65122009-08-06 18:41:42 -07001326 private boolean canTakePicture() {
1327 return isCameraIdle() && mPreviewing && (mPicturesRemaining > 0);
1328 }
1329
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001330 private void autoFocus() {
Wu-cheng Li05309122009-06-16 13:04:50 +08001331 // Initiate autofocus only when preview is started and snapshot is not
1332 // in progress.
repo syn && make -j4fcb65122009-08-06 18:41:42 -07001333 if (canTakePicture()) {
Wu-cheng Li5fa94832009-06-15 22:45:17 +08001334 Log.v(TAG, "Start autofocus.");
Wu-cheng Li35bda2d2009-09-27 20:45:42 -07001335 if (mZoomButtons != null) mZoomButtons.setVisible(false);
Wu-cheng Li5fa94832009-06-15 22:45:17 +08001336 mFocusStartTime = System.currentTimeMillis();
1337 mFocusState = FOCUSING;
1338 updateFocusIndicator();
1339 mCameraDevice.autoFocus(mAutoFocusCallback);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001340 }
1341 }
1342
Chih-Chung Chang62a2ae82009-09-15 15:33:39 +08001343 private void cancelAutoFocus() {
1344 // User releases half-pressed focus key.
1345 if (mFocusState == FOCUSING || mFocusState == FOCUS_SUCCESS
1346 || mFocusState == FOCUS_FAIL) {
1347 Log.v(TAG, "Cancel autofocus.");
1348 mCameraDevice.cancelAutoFocus();
1349 }
1350 if (mFocusState != FOCUSING_SNAP_ON_FINISH) {
1351 clearFocusState();
1352 }
1353 }
1354
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -08001355 private void clearFocusState() {
1356 mFocusState = FOCUS_NOT_STARTED;
Chih-Chung Chang5e5aa7e2009-04-21 18:24:13 +08001357 updateFocusIndicator();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001358 }
1359
1360 private void updateFocusIndicator() {
Owen Lin059daa32009-05-18 15:31:17 -07001361 if (mFocusRectangle == null) return;
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001362
Chih-Chung Chang75ae09f2009-04-23 17:20:42 +08001363 if (mFocusState == FOCUSING || mFocusState == FOCUSING_SNAP_ON_FINISH) {
1364 mFocusRectangle.showStart();
1365 } else if (mFocusState == FOCUS_SUCCESS) {
Chih-Chung Chang75ae09f2009-04-23 17:20:42 +08001366 mFocusRectangle.showSuccess();
1367 } else if (mFocusState == FOCUS_FAIL) {
Chih-Chung Chang75ae09f2009-04-23 17:20:42 +08001368 mFocusRectangle.showFail();
1369 } else {
Chih-Chung Chang75ae09f2009-04-23 17:20:42 +08001370 mFocusRectangle.clear();
1371 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001372 }
1373
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001374 @Override
Chih-Chung Chang0b8028e2009-09-25 15:12:14 -07001375 public void onBackPressed() {
1376 if (!isCameraIdle()) {
1377 // ignore backs while we're taking a picture
1378 return;
1379 }
1380 super.onBackPressed();
1381 }
1382
1383 @Override
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001384 public boolean onKeyDown(int keyCode, KeyEvent event) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001385 switch (keyCode) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001386 case KeyEvent.KEYCODE_FOCUS:
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001387 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
Dave Sparks11c53782009-03-24 22:20:14 -07001388 doFocus(true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001389 }
1390 return true;
1391 case KeyEvent.KEYCODE_CAMERA:
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001392 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
Dave Sparks11c53782009-03-24 22:20:14 -07001393 doSnap();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001394 }
1395 return true;
1396 case KeyEvent.KEYCODE_DPAD_CENTER:
Owen Lin0e841fe2009-04-09 07:41:20 -07001397 // If we get a dpad center event without any focused view, move
1398 // the focus to the shutter button and press it.
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001399 if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
Owen Lin0e841fe2009-04-09 07:41:20 -07001400 // Start auto-focus immediately to reduce shutter lag. After
1401 // the shutter button gets the focus, doFocus() will be
1402 // called again but it is fine.
Dave Sparks11c53782009-03-24 22:20:14 -07001403 doFocus(true);
1404 if (mShutterButton.isInTouchMode()) {
1405 mShutterButton.requestFocusFromTouch();
1406 } else {
1407 mShutterButton.requestFocus();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001408 }
Dave Sparks11c53782009-03-24 22:20:14 -07001409 mShutterButton.setPressed(true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001410 }
1411 return true;
1412 }
1413
1414 return super.onKeyDown(keyCode, event);
1415 }
1416
1417 @Override
1418 public boolean onKeyUp(int keyCode, KeyEvent event) {
1419 switch (keyCode) {
1420 case KeyEvent.KEYCODE_FOCUS:
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001421 if (mFirstTimeInitialized) {
1422 doFocus(false);
1423 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001424 return true;
Wei-Ta Chenbf45b962009-09-27 16:20:23 -07001425 case KeyEvent.KEYCODE_MENU:
1426 if (mIsImageCaptureIntent) {
1427 showOnScreenSettings();
1428 return true;
1429 }
1430 break;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001431 }
1432 return super.onKeyUp(keyCode, event);
1433 }
1434
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -08001435 private void doSnap() {
Wu-cheng Li083ccc12009-09-29 16:40:19 -07001436 Log.v(TAG, "doSnap: mFocusState=" + mFocusState);
Wu-cheng Li0f56ef52009-04-15 17:47:56 +08001437 // If the user has half-pressed the shutter and focus is completed, we
1438 // can take the photo right away. If the focus mode is infinity, we can
1439 // also take the photo.
Wu-cheng Lied6661e2009-09-21 08:54:43 +08001440 if (mFocusMode.equals(Parameters.FOCUS_MODE_INFINITY)
Chih-Chung Chang91acfc92009-07-06 15:37:24 +08001441 || (mFocusState == FOCUS_SUCCESS
1442 || mFocusState == FOCUS_FAIL)) {
Wu-cheng Li35bda2d2009-09-27 20:45:42 -07001443 if (mZoomButtons != null) mZoomButtons.setVisible(false);
Wu-cheng Li5fa94832009-06-15 22:45:17 +08001444 mImageCapture.onSnap();
The Android Open Source Project8d0dd0e2009-03-13 13:04:24 -07001445 } else if (mFocusState == FOCUSING) {
The Android Open Source Projectde365d82009-03-18 17:39:48 -07001446 // Half pressing the shutter (i.e. the focus button event) will
1447 // already have requested AF for us, so just request capture on
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -08001448 // focus here.
1449 mFocusState = FOCUSING_SNAP_ON_FINISH;
The Android Open Source Project8d0dd0e2009-03-13 13:04:24 -07001450 } else if (mFocusState == FOCUS_NOT_STARTED) {
1451 // Focus key down event is dropped for some reasons. Just ignore.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001452 }
1453 }
1454
1455 private void doFocus(boolean pressed) {
Wu-cheng Licc529322009-09-18 15:34:37 +08001456 // Do the focus if the mode is not infinity.
Wu-cheng Lied6661e2009-09-21 08:54:43 +08001457 if (!mFocusMode.equals(Parameters.FOCUS_MODE_INFINITY)) {
Wu-cheng Li0f56ef52009-04-15 17:47:56 +08001458 if (pressed) { // Focus key down.
Wu-cheng Li5fa94832009-06-15 22:45:17 +08001459 autoFocus();
Wu-cheng Li0f56ef52009-04-15 17:47:56 +08001460 } else { // Focus key up.
Chih-Chung Chang62a2ae82009-09-15 15:33:39 +08001461 cancelAutoFocus();
The Android Open Source Project9c9be2e2009-03-05 14:34:37 -08001462 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001463 }
1464 }
1465
1466 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Chih-Chung Chang4fc134d2009-06-18 10:56:41 +08001467 // Make sure we have a surface in the holder before proceeding.
1468 if (holder.getSurface() == null) {
1469 Log.d(TAG, "holder.getSurface() == null");
1470 return;
1471 }
1472
Wu-cheng Liba19d8b2009-09-02 16:53:37 +08001473 // The mCameraDevice will be null if it fails to connect to the camera
1474 // hardware. In this case we will show a dialog and then finish the
1475 // activity, so it's OK to ignore it.
Owen Lin3f3c8572009-08-18 13:33:49 +08001476 if (mCameraDevice == null) return;
1477
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +08001478 mSurfaceHolder = holder;
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +08001479
1480 // Sometimes surfaceChanged is called after onPause. Ignore it.
Owen Lin3f3c8572009-08-18 13:33:49 +08001481 if (mPausing || isFinishing()) return;
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +08001482
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +08001483 // Set preview display if the surface is being created. Preview was
1484 // already started.
1485 if (holder.isCreating()) {
1486 setPreviewDisplay(holder);
1487 }
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +08001488
1489 // If first time initialization is not finished, send a message to do
1490 // it later. We want to finish surfaceChanged as soon as possible to let
1491 // user see preview first.
1492 if (!mFirstTimeInitialized) {
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001493 mHandler.sendEmptyMessage(FIRST_TIME_INIT);
repo sync547caa32009-06-15 16:11:09 +08001494 } else {
1495 initializeSecondTime();
Wu-cheng Lie43adb12009-05-14 11:31:41 +08001496 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001497 }
1498
1499 public void surfaceCreated(SurfaceHolder holder) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001500 }
1501
1502 public void surfaceDestroyed(SurfaceHolder holder) {
1503 stopPreview();
1504 mSurfaceHolder = null;
1505 }
1506
1507 private void closeCamera() {
1508 if (mCameraDevice != null) {
Chih-Chung Changcd65be32009-06-09 13:51:29 +08001509 CameraHolder.instance().release();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001510 mCameraDevice = null;
1511 mPreviewing = false;
1512 }
1513 }
1514
Owen Lin3f3c8572009-08-18 13:33:49 +08001515 private void ensureCameraDevice() throws CameraHardwareException {
Dave Sparks11c53782009-03-24 22:20:14 -07001516 if (mCameraDevice == null) {
Chih-Chung Changcd65be32009-06-09 13:51:29 +08001517 mCameraDevice = CameraHolder.instance().open();
Cheng-Ru Lindf3731b2009-10-02 08:37:21 +08001518 mInitialParameters = mCameraDevice.getParameters();
Dave Sparks11c53782009-03-24 22:20:14 -07001519 }
Dave Sparks11c53782009-03-24 22:20:14 -07001520 }
1521
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001522 private void updateLastImage() {
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +08001523 IImageList list = ImageManager.makeImageList(
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001524 mContentResolver,
1525 dataLocation(),
1526 ImageManager.INCLUDE_IMAGES,
1527 ImageManager.SORT_ASCENDING,
1528 ImageManager.CAMERA_IMAGE_BUCKET_ID);
1529 int count = list.getCount();
1530 if (count > 0) {
Owen Lin0e841fe2009-04-09 07:41:20 -07001531 IImage image = list.getImageAt(count - 1);
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001532 Uri uri = image.fullSizeImageUri();
1533 mThumbController.setData(uri, image.miniThumbBitmap());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001534 } else {
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001535 mThumbController.setData(null, null);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001536 }
Chih-Chung Changf5bf8ca2009-08-25 18:28:29 +08001537 list.close();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001538 }
1539
Owen Lin3f3c8572009-08-18 13:33:49 +08001540 private void showCameraErrorAndFinish() {
1541 Resources ress = getResources();
1542 Util.showFatalErrorAndFinish(Camera.this,
1543 ress.getString(R.string.camera_error_title),
1544 ress.getString(R.string.cannot_connect_camera));
1545 }
1546
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001547 private void restartPreview() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001548 // make sure the surfaceview fills the whole screen when previewing
Owen Lin3f3c8572009-08-18 13:33:49 +08001549 try {
1550 startPreview();
1551 } catch (CameraHardwareException e) {
1552 showCameraErrorAndFinish();
1553 return;
1554 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001555
Owen Lin0e841fe2009-04-09 07:41:20 -07001556 // Calculate this in advance of each shot so we don't add to shutter
1557 // latency. It's true that someone else could write to the SD card in
1558 // the mean time and fill it, but that could have happened between the
1559 // shutter press and saving the JPEG too.
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001560 calculatePicturesRemaining();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001561 }
1562
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +08001563 private void setPreviewDisplay(SurfaceHolder holder) {
1564 try {
1565 mCameraDevice.setPreviewDisplay(holder);
1566 } catch (Throwable ex) {
1567 closeCamera();
1568 throw new RuntimeException("setPreviewDisplay failed", ex);
1569 }
1570 }
1571
Owen Lin3f3c8572009-08-18 13:33:49 +08001572 private void startPreview() throws CameraHardwareException {
1573 if (mPausing || isFinishing()) return;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001574
Owen Lin3f3c8572009-08-18 13:33:49 +08001575 ensureCameraDevice();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001576
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +08001577 // If we're previewing already, stop the preview first (this will blank
1578 // the screen).
Owen Lin0e841fe2009-04-09 07:41:20 -07001579 if (mPreviewing) stopPreview();
Dave Sparks11c53782009-03-24 22:20:14 -07001580
Wu-cheng Li48f6cdf2009-07-15 11:13:13 +08001581 setPreviewDisplay(mSurfaceHolder);
Wu-cheng Li75b9f0c2009-09-18 15:08:01 +08001582 setCameraParameters();
Dave Sparks11c53782009-03-24 22:20:14 -07001583
Dave Sparks11c53782009-03-24 22:20:14 -07001584 final long wallTimeStart = SystemClock.elapsedRealtime();
1585 final long threadTimeStart = Debug.threadCpuTimeNanos();
1586
Wu-cheng Libcd13fa2009-04-20 18:12:41 +08001587 // Set one shot preview callback for latency measurement.
1588 mCameraDevice.setOneShotPreviewCallback(mOneShotPreviewCallback);
Yu Shan Emily Laucede87f2009-07-02 18:07:17 -07001589 mCameraDevice.setErrorCallback(mErrorCallback);
Wu-cheng Libcd13fa2009-04-20 18:12:41 +08001590
Dave Sparks11c53782009-03-24 22:20:14 -07001591 try {
Wu-cheng Li8564b8a2009-06-16 18:25:33 +08001592 Log.v(TAG, "startPreview");
Dave Sparks11c53782009-03-24 22:20:14 -07001593 mCameraDevice.startPreview();
Wu-cheng Lifa1dfa22009-06-10 14:44:43 +08001594 } catch (Throwable ex) {
1595 closeCamera();
1596 throw new RuntimeException("startPreview failed", ex);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001597 }
Dave Sparks11c53782009-03-24 22:20:14 -07001598 mPreviewing = true;
Wu-cheng Li6cc6daf2009-06-10 16:52:37 +08001599 mStatus = IDLE;
Dave Sparks11c53782009-03-24 22:20:14 -07001600
Dave Sparks11c53782009-03-24 22:20:14 -07001601 long threadTimeEnd = Debug.threadCpuTimeNanos();
1602 long wallTimeEnd = SystemClock.elapsedRealtime();
1603 if ((wallTimeEnd - wallTimeStart) > 3000) {
Owen Lin0e841fe2009-04-09 07:41:20 -07001604 Log.w(TAG, "startPreview() to " + (wallTimeEnd - wallTimeStart)
1605 + " ms. Thread time was"
Dave Sparks11c53782009-03-24 22:20:14 -07001606 + (threadTimeEnd - threadTimeStart) / 1000000 + " ms.");
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001607 }
1608 }
1609
Wu-cheng Li5fa94832009-06-15 22:45:17 +08001610 private void stopPreview() {
1611 if (mCameraDevice != null && mPreviewing) {
Wu-cheng Li8564b8a2009-06-16 18:25:33 +08001612 Log.v(TAG, "stopPreview");
Wu-cheng Li5fa94832009-06-15 22:45:17 +08001613 mCameraDevice.stopPreview();
1614 }
1615 mPreviewing = false;
1616 // If auto focus was in progress, it would have been canceled.
1617 clearFocusState();
1618 }
1619
Cheng-Ru Linffcca742009-09-28 03:21:25 +08001620 private Size getOptimalPreviewSize(List<Size> sizes, double targetRatio) {
1621 final double ASPECT_TOLERANCE = 0.05;
1622 if (sizes == null) return null;
Wu-cheng Li4c37a762009-09-08 15:18:39 +08001623
Wu-cheng Li4c37a762009-09-08 15:18:39 +08001624 Size optimalSize = null;
Cheng-Ru Linffcca742009-09-28 03:21:25 +08001625 double minDiff = Double.MAX_VALUE;
1626
Cheng-Ru Lin542fa892009-10-03 02:05:13 +08001627 // Because of bugs of overlay and layout, we sometimes will try to
1628 // layout the viewfinder in the portrait orientation and thus get the
1629 // wrong size of mSurfaceView. When we change the preview size, the
1630 // new overlay will be created before the old one closed, which causes
1631 // an exception. For now, just get the screen size
1632
1633 Display display = getWindowManager().getDefaultDisplay();
1634 int targetHeight = Math.min(display.getHeight(), display.getWidth());
1635
Cheng-Ru Linffcca742009-09-28 03:21:25 +08001636 if (targetHeight <= 0) {
1637 // We don't know the size of SurefaceView, use screen height
1638 WindowManager windowManager = (WindowManager)
1639 getSystemService(Context.WINDOW_SERVICE);
1640 targetHeight = windowManager.getDefaultDisplay().getHeight();
1641 }
1642
1643 // Try to find an size match aspect ratio and size
1644 for (Size size : sizes) {
1645 double ratio = (double) size.width / size.height;
1646 if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
1647 if (Math.abs(size.height - targetHeight) < minDiff) {
1648 optimalSize = size;
1649 minDiff = Math.abs(size.height - targetHeight);
1650 }
1651 }
1652
1653 // Cannot find the one match the aspect ratio, ignore the requirement
1654 if (optimalSize == null) {
1655 Log.v(TAG, "No preview size match the aspect ratio");
1656 minDiff = Double.MAX_VALUE;
1657 for (Size size : sizes) {
1658 if (Math.abs(size.height - targetHeight) < minDiff) {
1659 optimalSize = size;
1660 minDiff = Math.abs(size.height - targetHeight);
Wu-cheng Li4c37a762009-09-08 15:18:39 +08001661 }
1662 }
Wu-cheng Li4c37a762009-09-08 15:18:39 +08001663 }
Cheng-Ru Linffcca742009-09-28 03:21:25 +08001664 Log.v(TAG, String.format(
1665 "Optimal preview size is %sx%s",
1666 optimalSize.width, optimalSize.height));
Wu-cheng Li4c37a762009-09-08 15:18:39 +08001667 return optimalSize;
1668 }
1669
Owen Lindbb23f72009-09-19 22:12:48 +08001670 private static boolean isSupported(String value, List<String> supported) {
1671 return supported == null ? false : supported.indexOf(value) >= 0;
1672 }
1673
Wu-cheng Li75b9f0c2009-09-18 15:08:01 +08001674 private void setCameraParameters() {
Wu-cheng Lie0770002009-04-13 07:02:51 -07001675 mParameters = mCameraDevice.getParameters();
Wu-cheng Li59457732009-08-03 22:25:29 +08001676
Wu-cheng Licc5a6352009-09-08 12:21:52 +08001677 // Reset preview frame rate to the maximum because it may be lowered by
1678 // video camera application.
1679 List<Integer> frameRates = mParameters.getSupportedPreviewFrameRates();
1680 if (frameRates != null) {
1681 Integer max = Collections.max(frameRates);
1682 mParameters.setPreviewFrameRate(max);
1683 }
1684
Wu-cheng Li59457732009-08-03 22:25:29 +08001685 // Set picture size.
Owen Lin2c6c6172009-09-01 14:51:53 +08001686 String pictureSize = mPreferences.getString(
Owen Lin32bfffa2009-09-19 19:50:42 +08001687 CameraSettings.KEY_PICTURE_SIZE, null);
1688 if (pictureSize == null) {
1689 CameraSettings.initialCameraPictureSize(this, mParameters);
1690 } else {
1691 List<Size> supported = mParameters.getSupportedPictureSizes();
1692 CameraSettings.setCameraPictureSize(
1693 pictureSize, supported, mParameters);
1694 }
Owen Lin937fc482009-04-14 02:02:51 -07001695
Cheng-Ru Linffcca742009-09-28 03:21:25 +08001696 // Set the preview frame aspect ratio according to the picture size.
1697 Size size = mParameters.getPictureSize();
1698 PreviewFrameLayout frameLayout =
1699 (PreviewFrameLayout) findViewById(R.id.frame_layout);
1700 frameLayout.setAspectRatio((double) size.width / size.height);
1701
1702 // Set a preview size that is closest to the viewfinder height and has
1703 // the right aspect ratio.
1704 List<Size> sizes = mParameters.getSupportedPreviewSizes();
1705 Size optimalSize = getOptimalPreviewSize(
1706 sizes, (double) size.width / size.height);
1707 if (optimalSize != null) {
1708 mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
1709 }
1710
Wu-cheng Li59457732009-08-03 22:25:29 +08001711 // Set JPEG quality.
Wu-cheng Lie0770002009-04-13 07:02:51 -07001712 String jpegQuality = mPreferences.getString(
1713 CameraSettings.KEY_JPEG_QUALITY,
1714 getString(R.string.pref_camera_jpegquality_default));
Wu-cheng Li4305c702009-09-02 16:33:59 +08001715 mParameters.setJpegQuality(Integer.parseInt(jpegQuality));
Owen Lin937fc482009-04-14 02:02:51 -07001716
Owen Lindbb23f72009-09-19 22:12:48 +08001717 // For the following settings, we need to check if the settings are
1718 // still supported by latest driver, if not, ignore the settings.
1719
Owen Lindbb23f72009-09-19 22:12:48 +08001720 // Set color effect parameter.
1721 String colorEffect = mPreferences.getString(
1722 CameraSettings.KEY_COLOR_EFFECT,
1723 getString(R.string.pref_camera_coloreffect_default));
1724 if (isSupported(colorEffect, mParameters.getSupportedColorEffects())) {
President Li5f6484a2009-04-02 02:38:09 -07001725 mParameters.setColorEffect(colorEffect);
1726 }
1727
Wu-cheng Li75b9f0c2009-09-18 15:08:01 +08001728 // Set scene mode.
Wu-cheng Lied6661e2009-09-21 08:54:43 +08001729 String sceneMode = mPreferences.getString(
1730 CameraSettings.KEY_SCENE_MODE,
1731 getString(R.string.pref_camera_scenemode_default));
1732 if (isSupported(sceneMode, mParameters.getSupportedSceneModes())) {
Wu-cheng Li75b9f0c2009-09-18 15:08:01 +08001733 mParameters.setSceneMode(sceneMode);
Cheng-Ru Lin3b90cce2009-10-01 11:42:29 +08001734 } else {
1735 sceneMode = mParameters.getSceneMode();
1736 if (sceneMode == null) {
1737 sceneMode = Parameters.SCENE_MODE_AUTO;
1738 }
Wu-cheng Li75b9f0c2009-09-18 15:08:01 +08001739 }
1740
Cheng-Ru Lin301c0882009-10-01 05:51:22 +08001741 // If scene mode is set, we cannot set flash mode, white balance, and
1742 // focus mode, instead, we read it from driver
1743 String flashMode;
1744 String whiteBalance;
1745
1746 if (!Parameters.SCENE_MODE_AUTO.equals(sceneMode)) {
1747 mCameraDevice.setParameters(mParameters);
1748
1749 // Setting scene mode will change the settings of flash mode, white
1750 // balance, and focus mode. So read back here, so that we know
1751 // what's the settings
1752 mParameters = mCameraDevice.getParameters();
1753 flashMode = mParameters.getFlashMode();
1754 whiteBalance = mParameters.getWhiteBalance();
1755 mFocusMode = mParameters.getFocusMode();
1756 if (mSettings != null) {
1757 mSettings.overrideSettings(
1758 CameraSettings.KEY_FLASH_MODE, flashMode);
1759 mSettings.overrideSettings(
1760 CameraSettings.KEY_WHITE_BALANCE, whiteBalance);
1761 mSettings.overrideSettings(
1762 CameraSettings.KEY_FOCUS_MODE, mFocusMode);
1763 }
1764 } else {
1765 if (mSettings != null) {
1766 mSettings.overrideSettings(CameraSettings.KEY_FLASH_MODE, null);
1767 mSettings.overrideSettings(CameraSettings.KEY_FOCUS_MODE, null);
1768 mSettings.overrideSettings(
1769 CameraSettings.KEY_WHITE_BALANCE, null);
1770 }
1771
1772 // Set flash mode.
1773 flashMode = mPreferences.getString(
1774 CameraSettings.KEY_FLASH_MODE,
1775 getString(R.string.pref_camera_flashmode_default));
1776 List<String> supportedFlash = mParameters.getSupportedFlashModes();
1777 if (isSupported(flashMode, supportedFlash)) {
1778 mParameters.setFlashMode(flashMode);
1779 } else {
Cheng-Ru Lin3b90cce2009-10-01 11:42:29 +08001780 flashMode = mParameters.getFlashMode();
1781 if (flashMode == null) {
Owen Lin12f4b9a2009-10-05 18:13:06 -07001782 flashMode = NO_FLASH_MODE;
Cheng-Ru Lin3b90cce2009-10-01 11:42:29 +08001783 }
Cheng-Ru Lin301c0882009-10-01 05:51:22 +08001784 }
1785
1786 // Set white balance parameter.
1787 whiteBalance = mPreferences.getString(
1788 CameraSettings.KEY_WHITE_BALANCE,
1789 getString(R.string.pref_camera_whitebalance_default));
1790 if (isSupported(whiteBalance, mParameters.getSupportedWhiteBalance())) {
1791 mParameters.setWhiteBalance(whiteBalance);
Cheng-Ru Lin3b90cce2009-10-01 11:42:29 +08001792 } else {
1793 whiteBalance = mParameters.getWhiteBalance();
1794 if (whiteBalance == null) {
1795 whiteBalance = Parameters.WHITE_BALANCE_AUTO;
1796 }
Cheng-Ru Lin301c0882009-10-01 05:51:22 +08001797 }
1798
1799 // Set focus mode.
1800 mFocusMode = mPreferences.getString(
1801 CameraSettings.KEY_FOCUS_MODE,
1802 getString(R.string.pref_camera_focusmode_default));
1803 if (isSupported(mFocusMode, mParameters.getSupportedFocusModes())) {
1804 mParameters.setFocusMode(mFocusMode);
Cheng-Ru Lin3b90cce2009-10-01 11:42:29 +08001805 } else {
1806 mFocusMode = mParameters.getFocusMode();
1807 if (mFocusMode == null) {
1808 mFocusMode = Parameters.FOCUS_MODE_AUTO;
1809 }
Cheng-Ru Lin301c0882009-10-01 05:51:22 +08001810 }
Cheng-Ru Lin3b90cce2009-10-01 11:42:29 +08001811
Cheng-Ru Lin301c0882009-10-01 05:51:22 +08001812 mCameraDevice.setParameters(mParameters);
Wu-cheng Licc529322009-09-18 15:34:37 +08001813 }
1814
Cheng-Ru Lin27e69922009-09-30 13:48:59 +08001815 // We post the runner because this function can be called from
1816 // non-UI thread (i.e., startPreviewThread).
Cheng-Ru Lin25156f02009-10-01 00:34:41 +08001817 final String finalWhiteBalance = whiteBalance;
Cheng-Ru Lin27e69922009-09-30 13:48:59 +08001818 final String finalFlashMode = flashMode;
Cheng-Ru Lin25156f02009-10-01 00:34:41 +08001819 final String finalSceneMode =
Cheng-Ru Lin52de1512009-10-01 13:29:06 +08001820 Parameters.SCENE_MODE_AUTO.equals(sceneMode)
Cheng-Ru Lin25156f02009-10-01 00:34:41 +08001821 ? SCENE_MODE_OFF
1822 : SCENE_MODE_ON;
Cheng-Ru Lin27e69922009-09-30 13:48:59 +08001823
1824 mHandler.post(new Runnable() {
1825 public void run() {
1826 mFocusIndicator.setMode(mFocusMode);
1827 mWhitebalanceIndicator.setMode(finalWhiteBalance);
Cheng-Ru Lin25156f02009-10-01 00:34:41 +08001828 mSceneModeIndicator.setMode(finalSceneMode);
Cheng-Ru Lin27e69922009-09-30 13:48:59 +08001829 mFlashIndicator.setMode(finalFlashMode);
1830 }
1831 });
Wu-cheng Lie0770002009-04-13 07:02:51 -07001832 }
1833
Chih-Chung Chang522e8362009-08-26 16:12:34 +08001834 private void gotoGallery() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001835 MenuHelper.gotoCameraImageGallery(this);
1836 }
1837
1838 private void viewLastImage() {
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001839 if (mThumbController.isUriValid()) {
1840 Uri targetUri = mThumbController.getUri();
Owen Lin0e841fe2009-04-09 07:41:20 -07001841 targetUri = targetUri.buildUpon().appendQueryParameter(
1842 "bucketId", ImageManager.CAMERA_IMAGE_BUCKET_ID).build();
Wu-cheng Li46fc7ae2009-06-19 19:28:47 +08001843 Intent intent = new Intent(this, ReviewImage.class);
1844 intent.setData(targetUri);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001845 intent.putExtra(MediaStore.EXTRA_FULL_SCREEN, true);
1846 intent.putExtra(MediaStore.EXTRA_SHOW_ACTION_ICONS, true);
1847 intent.putExtra("com.android.camera.ReviewMode", true);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001848 try {
1849 startActivity(intent);
Owen Lin0e841fe2009-04-09 07:41:20 -07001850 } catch (ActivityNotFoundException ex) {
Owen Lin0ce26e02009-05-05 15:43:54 -07001851 Log.e(TAG, "review image fail", ex);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001852 }
1853 } else {
1854 Log.e(TAG, "Can't view last image.");
1855 }
1856 }
1857
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001858 private void startReceivingLocationUpdates() {
1859 if (mLocationManager != null) {
1860 try {
1861 mLocationManager.requestLocationUpdates(
1862 LocationManager.NETWORK_PROVIDER,
1863 1000,
1864 0F,
1865 mLocationListeners[1]);
1866 } catch (java.lang.SecurityException ex) {
Owen Lindeb57252009-05-27 14:55:45 -07001867 Log.i(TAG, "fail to request location update, ignore", ex);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001868 } catch (IllegalArgumentException ex) {
Owen Lindeb57252009-05-27 14:55:45 -07001869 Log.d(TAG, "provider does not exist " + ex.getMessage());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001870 }
1871 try {
1872 mLocationManager.requestLocationUpdates(
1873 LocationManager.GPS_PROVIDER,
1874 1000,
1875 0F,
1876 mLocationListeners[0]);
1877 } catch (java.lang.SecurityException ex) {
Owen Lindeb57252009-05-27 14:55:45 -07001878 Log.i(TAG, "fail to request location update, ignore", ex);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001879 } catch (IllegalArgumentException ex) {
Owen Lindeb57252009-05-27 14:55:45 -07001880 Log.d(TAG, "provider does not exist " + ex.getMessage());
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001881 }
1882 }
1883 }
1884
1885 private void stopReceivingLocationUpdates() {
1886 if (mLocationManager != null) {
1887 for (int i = 0; i < mLocationListeners.length; i++) {
1888 try {
1889 mLocationManager.removeUpdates(mLocationListeners[i]);
1890 } catch (Exception ex) {
Owen Lindeb57252009-05-27 14:55:45 -07001891 Log.i(TAG, "fail to remove location listners, ignore", ex);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001892 }
1893 }
1894 }
1895 }
1896
1897 private Location getCurrentLocation() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001898 // go in best to worst order
1899 for (int i = 0; i < mLocationListeners.length; i++) {
Owen Lin07c90562009-03-24 19:38:57 -07001900 Location l = mLocationListeners[i].current();
1901 if (l != null) return l;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001902 }
Owen Lin07c90562009-03-24 19:38:57 -07001903 return null;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001904 }
1905
Wu-cheng Li5fa94832009-06-15 22:45:17 +08001906 private boolean isCameraIdle() {
1907 return mStatus == IDLE && mFocusState == FOCUS_NOT_STARTED;
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001908 }
1909
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001910 private boolean isImageCaptureIntent() {
1911 String action = getIntent().getAction();
1912 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action));
1913 }
1914
Chih-Chung Changcd972b02009-09-22 16:47:43 -07001915 private void setupCaptureParams() {
1916 Bundle myExtras = getIntent().getExtras();
1917 if (myExtras != null) {
1918 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
1919 mCropValue = myExtras.getString("crop");
Chih-Chung Changcd972b02009-09-22 16:47:43 -07001920 }
1921 }
1922
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001923 private void showPostCaptureAlert() {
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001924 if (mIsImageCaptureIntent) {
Owen Lin61b98312009-06-19 00:21:10 -07001925 findViewById(R.id.shutter_button).setVisibility(View.INVISIBLE);
1926 int[] pickIds = {R.id.btn_retake, R.id.btn_done};
Owen Lin0e841fe2009-04-09 07:41:20 -07001927 for (int id : pickIds) {
Owen Lin61b98312009-06-19 00:21:10 -07001928 View button = findViewById(id);
1929 ((View) button.getParent()).setVisibility(View.VISIBLE);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001930 }
1931 }
1932 }
1933
1934 private void hidePostCaptureAlert() {
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001935 if (mIsImageCaptureIntent) {
Owen Lin61b98312009-06-19 00:21:10 -07001936 findViewById(R.id.shutter_button).setVisibility(View.VISIBLE);
1937 int[] pickIds = {R.id.btn_retake, R.id.btn_done};
1938 for (int id : pickIds) {
1939 View button = findViewById(id);
1940 ((View) button.getParent()).setVisibility(View.GONE);
1941 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001942 }
1943 }
1944
Wu-cheng Li5fa94832009-06-15 22:45:17 +08001945 private int calculatePicturesRemaining() {
1946 mPicturesRemaining = MenuHelper.calculatePicturesRemaining();
1947 return mPicturesRemaining;
1948 }
1949
1950 @Override
1951 public boolean onPrepareOptionsMenu(Menu menu) {
1952 super.onPrepareOptionsMenu(menu);
Wu-cheng Li5fa94832009-06-15 22:45:17 +08001953 // Only show the menu when camera is idle.
Chih-Chung Changb5946542009-09-07 20:17:12 +08001954 for (int i = 0; i < menu.size(); i++) {
1955 menu.getItem(i).setVisible(isCameraIdle());
Wu-cheng Li5fa94832009-06-15 22:45:17 +08001956 }
1957
1958 return true;
1959 }
1960
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001961 @Override
1962 public boolean onCreateOptionsMenu(Menu menu) {
1963 super.onCreateOptionsMenu(menu);
1964
Chih-Chung Chang9bc8d1b2009-03-24 19:22:29 -07001965 if (mIsImageCaptureIntent) {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001966 // No options menu for attach mode.
1967 return false;
1968 } else {
1969 addBaseMenuItems(menu);
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001970 }
1971 return true;
1972 }
1973
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001974 private void addBaseMenuItems(Menu menu) {
Chih-Chung Changd1890832009-09-08 13:32:52 +08001975 MenuItem gallery = menu.add(Menu.NONE, Menu.NONE,
1976 MenuHelper.POSITION_GOTO_GALLERY,
Chih-Chung Changb5946542009-09-07 20:17:12 +08001977 R.string.camera_gallery_photos_text)
1978 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
1979 public boolean onMenuItemClick(MenuItem item) {
1980 gotoGallery();
1981 return true;
1982 }
1983 });
1984 gallery.setIcon(android.R.drawable.ic_menu_gallery);
1985 mGalleryItems.add(gallery);
1986
Chih-Chung Changd1890832009-09-08 13:32:52 +08001987 MenuItem item = menu.add(Menu.NONE, Menu.NONE,
1988 MenuHelper.POSITION_CAMERA_SETTING, R.string.settings)
Owen Lin0e841fe2009-04-09 07:41:20 -07001989 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001990 public boolean onMenuItemClick(MenuItem item) {
Owen Linc1f2e302009-09-14 19:04:37 +08001991 showOnScreenSettings();
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08001992 return true;
1993 }
1994 });
1995 item.setIcon(android.R.drawable.ic_menu_preferences);
1996 }
Owen Line239acc2009-06-23 22:18:20 -07001997
Chih-Chung Changd918cfa2009-07-13 13:11:52 +08001998 public boolean onSwitchChanged(Switcher source, boolean onOff) {
1999 if (onOff == SWITCH_VIDEO) {
2000 if (!isCameraIdle()) return false;
Owen Line239acc2009-06-23 22:18:20 -07002001 MenuHelper.gotoVideoMode(this);
Owen Lin3283e042009-06-26 11:59:58 -07002002 finish();
Owen Line239acc2009-06-23 22:18:20 -07002003 }
Chih-Chung Changd918cfa2009-07-13 13:11:52 +08002004 return true;
Owen Line239acc2009-06-23 22:18:20 -07002005 }
Chih-Chung Chang8df283a2009-08-21 19:25:48 +08002006
Owen Lin2c6c6172009-09-01 14:51:53 +08002007 public void onSharedPreferenceChanged(
2008 SharedPreferences preferences, String key) {
2009 // ignore the events after "onPause()"
2010 if (mPausing) return;
2011
Wu-cheng Licc529322009-09-18 15:34:37 +08002012 if (CameraSettings.KEY_RECORD_LOCATION.equals(key)) {
Owen Lin2c6c6172009-09-01 14:51:53 +08002013 mRecordLocation = preferences.getBoolean(key, false);
2014 if (mRecordLocation) {
2015 startReceivingLocationUpdates();
2016 } else {
2017 stopReceivingLocationUpdates();
2018 }
Wu-cheng Licc529322009-09-18 15:34:37 +08002019 } else {
2020 // All preferences except RECORD_LOCATION are camera parameters.
2021 // Call setCameraParameters to take effect now.
2022 setCameraParameters();
Owen Lin2c6c6172009-09-01 14:51:53 +08002023 }
2024 }
Owen Lincc8d7562009-09-16 14:43:09 +08002025
2026 @Override
2027 public void onUserInteraction() {
2028 super.onUserInteraction();
2029 keepScreenOnAwhile();
2030 }
2031
2032 private void resetScreenOn() {
2033 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
2034 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
2035 }
2036
2037 private void keepScreenOnAwhile() {
2038 mHandler.removeMessages(CLEAR_SCREEN_DELAY);
2039 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
2040 mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY);
2041 }
The Android Open Source Projectb64d3452009-03-03 19:32:20 -08002042}
Chih-Chung Chang5e5aa7e2009-04-21 18:24:13 +08002043
2044class FocusRectangle extends View {
Owen Lindeb57252009-05-27 14:55:45 -07002045
2046 @SuppressWarnings("unused")
Chih-Chung Chang5e5aa7e2009-04-21 18:24:13 +08002047 private static final String TAG = "FocusRectangle";
2048
2049 public FocusRectangle(Context context, AttributeSet attrs) {
2050 super(context, attrs);
2051 }
2052
2053 private void setDrawable(int resid) {
Owen Lindad4b182009-06-11 16:02:29 -07002054 setBackgroundDrawable(getResources().getDrawable(resid));
Chih-Chung Chang5e5aa7e2009-04-21 18:24:13 +08002055 }
2056
2057 public void showStart() {
Owen Lindad4b182009-06-11 16:02:29 -07002058 setDrawable(R.drawable.focus_focusing);
Chih-Chung Chang5e5aa7e2009-04-21 18:24:13 +08002059 }
2060
2061 public void showSuccess() {
Owen Lindad4b182009-06-11 16:02:29 -07002062 setDrawable(R.drawable.focus_focused);
Chih-Chung Chang5e5aa7e2009-04-21 18:24:13 +08002063 }
2064
2065 public void showFail() {
Owen Lindad4b182009-06-11 16:02:29 -07002066 setDrawable(R.drawable.focus_focus_failed);
Chih-Chung Chang5e5aa7e2009-04-21 18:24:13 +08002067 }
2068
2069 public void clear() {
2070 setBackgroundDrawable(null);
2071 }
2072}