Camera.java revision a93a4d60eacee4e12471b45f8691c14114e113a4
1/* 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 19import com.android.camera.ui.CameraPicker; 20import com.android.camera.ui.FaceView; 21import com.android.camera.ui.IndicatorControlContainer; 22import com.android.camera.ui.RotateImageView; 23import com.android.camera.ui.RotateLayout; 24import com.android.camera.ui.SharePopup; 25import com.android.camera.ui.ZoomControl; 26 27import android.app.Activity; 28import android.content.BroadcastReceiver; 29import android.content.ContentProviderClient; 30import android.content.ContentResolver; 31import android.content.Context; 32import android.content.Intent; 33import android.content.IntentFilter; 34import android.content.SharedPreferences.Editor; 35import android.graphics.Bitmap; 36import android.hardware.Camera.CameraInfo; 37import android.hardware.Camera.Face; 38import android.hardware.Camera.FaceDetectionListener; 39import android.hardware.Camera.Parameters; 40import android.hardware.Camera.PictureCallback; 41import android.hardware.Camera.Size; 42import android.location.Location; 43import android.media.CameraProfile; 44import android.net.Uri; 45import android.os.Bundle; 46import android.os.Handler; 47import android.os.Looper; 48import android.os.Message; 49import android.os.MessageQueue; 50import android.os.SystemClock; 51import android.provider.MediaStore; 52import android.provider.Settings; 53import android.util.Log; 54import android.view.GestureDetector; 55import android.view.Gravity; 56import android.view.KeyEvent; 57import android.view.Menu; 58import android.view.MenuItem; 59import android.view.MenuItem.OnMenuItemClickListener; 60import android.view.MotionEvent; 61import android.view.OrientationEventListener; 62import android.view.SurfaceHolder; 63import android.view.SurfaceView; 64import android.view.View; 65import android.view.Window; 66import android.view.WindowManager; 67import android.view.animation.AnimationUtils; 68import android.widget.TextView; 69import android.widget.Toast; 70 71import java.io.File; 72import java.io.FileNotFoundException; 73import java.io.FileOutputStream; 74import java.io.IOException; 75import java.io.OutputStream; 76import java.util.ArrayList; 77import java.util.Collections; 78import java.util.Formatter; 79import java.util.List; 80 81/** The Camera activity which can preview and take pictures. */ 82public class Camera extends ActivityBase implements FocusManager.Listener, 83 View.OnTouchListener, ShutterButton.OnShutterButtonListener, 84 SurfaceHolder.Callback, ModePicker.OnModeChangeListener, 85 FaceDetectionListener, CameraPreference.OnPreferenceChangedListener, 86 LocationManager.Listener { 87 88 private static final String TAG = "camera"; 89 90 private static final String LAST_THUMB_FILENAME = "image_last_thumb"; 91 92 private static final int CROP_MSG = 1; 93 private static final int FIRST_TIME_INIT = 2; 94 private static final int RESTART_PREVIEW = 3; 95 private static final int CLEAR_SCREEN_DELAY = 4; 96 private static final int SET_CAMERA_PARAMETERS_WHEN_IDLE = 5; 97 private static final int CHECK_DISPLAY_ROTATION = 6; 98 private static final int SHOW_TAP_TO_FOCUS_TOAST = 7; 99 private static final int DISMISS_TAP_TO_FOCUS_TOAST = 8; 100 101 // The subset of parameters we need to update in setCameraParameters(). 102 private static final int UPDATE_PARAM_INITIALIZE = 1; 103 private static final int UPDATE_PARAM_ZOOM = 2; 104 private static final int UPDATE_PARAM_PREFERENCE = 4; 105 private static final int UPDATE_PARAM_ALL = -1; 106 107 // When setCameraParametersWhenIdle() is called, we accumulate the subsets 108 // needed to be updated in mUpdateSet. 109 private int mUpdateSet; 110 111 // The brightness settings used when it is set to automatic in the system. 112 // The reason why it is set to 0.7 is just because 1.0 is too bright. 113 private static final float DEFAULT_CAMERA_BRIGHTNESS = 0.7f; 114 115 private static final int SCREEN_DELAY = 2 * 60 * 1000; 116 117 private static final int ZOOM_STOPPED = 0; 118 private static final int ZOOM_START = 1; 119 private static final int ZOOM_STOPPING = 2; 120 121 private int mZoomState = ZOOM_STOPPED; 122 private boolean mSmoothZoomSupported = false; 123 private int mZoomValue; // The current zoom value. 124 private int mZoomMax; 125 private int mTargetZoomValue; 126 private ZoomControl mZoomControl; 127 128 private Parameters mParameters; 129 private Parameters mInitialParams; 130 private boolean mFocusAreaSupported; 131 private boolean mMeteringAreaSupported; 132 133 private MyOrientationEventListener mOrientationListener; 134 // The degrees of the device rotated clockwise from its natural orientation. 135 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; 136 // The orientation compensation for icons and thumbnails. Ex: if the value 137 // is 90, the UI components should be rotated 90 degrees counter-clockwise. 138 private int mOrientationCompensation = 0; 139 private ComboPreferences mPreferences; 140 141 private static final String sTempCropFilename = "crop-temp"; 142 143 private android.hardware.Camera mCameraDevice; 144 private ContentProviderClient mMediaProviderClient; 145 private SurfaceHolder mSurfaceHolder = null; 146 private ShutterButton mShutterButton; 147 private GestureDetector mPopupGestureDetector; 148 private boolean mOpenCameraFail = false; 149 private boolean mCameraDisabled = false; 150 151 private PreviewFrameLayout mPreviewFrameLayout; 152 private View mPreviewFrame; // Preview frame area. 153 private View mPreviewBorder; 154 155 // A popup window that contains a bigger thumbnail and a list of apps to share. 156 private SharePopup mSharePopup; 157 // The bitmap of the last captured picture thumbnail and the URI of the 158 // original picture. 159 private Thumbnail mThumbnail; 160 // An imageview showing showing the last captured picture thumbnail. 161 private RotateImageView mThumbnailView; 162 private ModePicker mModePicker; 163 private FaceView mFaceView; 164 private RotateLayout mFocusIndicator; 165 166 // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true. 167 private String mCropValue; 168 private Uri mSaveUri; 169 170 // On-screen indicator 171 private View mGpsNoSignalIndicator; 172 private View mGpsHasSignalIndicator; 173 private TextView mExposureIndicator; 174 175 private final StringBuilder mBuilder = new StringBuilder(); 176 private final Formatter mFormatter = new Formatter(mBuilder); 177 private final Object[] mFormatterArgs = new Object[1]; 178 179 /** 180 * An unpublished intent flag requesting to return as soon as capturing 181 * is completed. 182 * 183 * TODO: consider publishing by moving into MediaStore. 184 */ 185 private final static String EXTRA_QUICK_CAPTURE = 186 "android.intent.extra.quickCapture"; 187 188 // The display rotation in degrees. This is only valid when mCameraState is 189 // not PREVIEW_STOPPED. 190 private int mDisplayRotation; 191 // The value for android.hardware.Camera.setDisplayOrientation. 192 private int mDisplayOrientation; 193 private boolean mPausing; 194 private boolean mFirstTimeInitialized; 195 private boolean mIsImageCaptureIntent; 196 197 private static final int PREVIEW_STOPPED = 0; 198 private static final int IDLE = 1; // preview is active 199 // Focus is in progress. The exact focus state is in Focus.java. 200 private static final int FOCUSING = 2; 201 private static final int SNAPSHOT_IN_PROGRESS = 3; 202 private int mCameraState = PREVIEW_STOPPED; 203 204 private ContentResolver mContentResolver; 205 private boolean mDidRegister = false; 206 207 private final ArrayList<MenuItem> mGalleryItems = new ArrayList<MenuItem>(); 208 209 private LocationManager mLocationManager; 210 211 private final ShutterCallback mShutterCallback = new ShutterCallback(); 212 private final PostViewPictureCallback mPostViewPictureCallback = 213 new PostViewPictureCallback(); 214 private final RawPictureCallback mRawPictureCallback = 215 new RawPictureCallback(); 216 private final AutoFocusCallback mAutoFocusCallback = 217 new AutoFocusCallback(); 218 private final ZoomListener mZoomListener = new ZoomListener(); 219 private final CameraErrorCallback mErrorCallback = new CameraErrorCallback(); 220 221 private long mFocusStartTime; 222 private long mCaptureStartTime; 223 private long mShutterCallbackTime; 224 private long mPostViewPictureCallbackTime; 225 private long mRawPictureCallbackTime; 226 private long mJpegPictureCallbackTime; 227 private long mOnResumeTime; 228 private long mPicturesRemaining; 229 private byte[] mJpegImageData; 230 231 // These latency time are for the CameraLatency test. 232 public long mAutoFocusTime; 233 public long mShutterLag; 234 public long mShutterToPictureDisplayedTime; 235 public long mPictureDisplayedToJpegCallbackTime; 236 public long mJpegCallbackFinishTime; 237 238 // This handles everything about focus. 239 private FocusManager mFocusManager; 240 private String mSceneMode; 241 private Toast mNotSelectableToast; 242 private Toast mNoShareToast; 243 244 private final Handler mHandler = new MainHandler(); 245 private IndicatorControlContainer mIndicatorControlContainer; 246 private PreferenceGroup mPreferenceGroup; 247 248 // multiple cameras support 249 private int mNumberOfCameras; 250 private int mCameraId; 251 private int mFrontCameraId; 252 private int mBackCameraId; 253 254 private boolean mQuickCapture; 255 256 /** 257 * This Handler is used to post message back onto the main thread of the 258 * application 259 */ 260 private class MainHandler extends Handler { 261 @Override 262 public void handleMessage(Message msg) { 263 switch (msg.what) { 264 case RESTART_PREVIEW: { 265 startPreview(); 266 if (mJpegPictureCallbackTime != 0) { 267 long now = System.currentTimeMillis(); 268 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime; 269 Log.v(TAG, "mJpegCallbackFinishTime = " 270 + mJpegCallbackFinishTime + "ms"); 271 mJpegPictureCallbackTime = 0; 272 } 273 break; 274 } 275 276 case CLEAR_SCREEN_DELAY: { 277 getWindow().clearFlags( 278 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 279 break; 280 } 281 282 case FIRST_TIME_INIT: { 283 initializeFirstTime(); 284 break; 285 } 286 287 case SET_CAMERA_PARAMETERS_WHEN_IDLE: { 288 setCameraParametersWhenIdle(0); 289 break; 290 } 291 292 case CHECK_DISPLAY_ROTATION: { 293 // Restart the preview if display rotation has changed. 294 // Sometimes this happens when the device is held upside 295 // down and camera app is opened. Rotation animation will 296 // take some time and the rotation value we have got may be 297 // wrong. Framework does not have a callback for this now. 298 if (Util.getDisplayRotation(Camera.this) != mDisplayRotation 299 && isCameraIdle()) { 300 startPreview(); 301 } 302 if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) { 303 mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100); 304 } 305 break; 306 } 307 308 case SHOW_TAP_TO_FOCUS_TOAST: { 309 showTapToFocusToast(); 310 break; 311 } 312 313 case DISMISS_TAP_TO_FOCUS_TOAST: { 314 View v = findViewById(R.id.tap_to_focus_prompt); 315 v.setVisibility(View.GONE); 316 v.setAnimation(AnimationUtils.loadAnimation(Camera.this, 317 R.anim.on_screen_hint_exit)); 318 break; 319 } 320 } 321 } 322 } 323 324 private void resetExposureCompensation() { 325 String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE, 326 CameraSettings.EXPOSURE_DEFAULT_VALUE); 327 if (!CameraSettings.EXPOSURE_DEFAULT_VALUE.equals(value)) { 328 Editor editor = mPreferences.edit(); 329 editor.putString(CameraSettings.KEY_EXPOSURE, "0"); 330 editor.apply(); 331 if (mIndicatorControlContainer != null) { 332 mIndicatorControlContainer.reloadPreferences(); 333 } 334 } 335 } 336 337 private void keepMediaProviderInstance() { 338 // We want to keep a reference to MediaProvider in camera's lifecycle. 339 // TODO: Utilize mMediaProviderClient instance to replace 340 // ContentResolver calls. 341 if (mMediaProviderClient == null) { 342 mMediaProviderClient = getContentResolver() 343 .acquireContentProviderClient(MediaStore.AUTHORITY); 344 } 345 } 346 347 // Snapshots can only be taken after this is called. It should be called 348 // once only. We could have done these things in onCreate() but we want to 349 // make preview screen appear as soon as possible. 350 private void initializeFirstTime() { 351 if (mFirstTimeInitialized) return; 352 353 // Create orientation listenter. This should be done first because it 354 // takes some time to get first orientation. 355 mOrientationListener = new MyOrientationEventListener(Camera.this); 356 mOrientationListener.enable(); 357 358 // Initialize location sevice. 359 boolean recordLocation = RecordLocationPreference.get( 360 mPreferences, getContentResolver()); 361 initOnScreenIndicator(); 362 mLocationManager.recordLocation(recordLocation); 363 364 keepMediaProviderInstance(); 365 checkStorage(); 366 367 // Initialize last picture button. 368 mContentResolver = getContentResolver(); 369 if (!mIsImageCaptureIntent) { // no thumbnail in image capture intent 370 initThumbnailButton(); 371 } 372 373 // Initialize shutter button. 374 mShutterButton = (ShutterButton) findViewById(R.id.shutter_button); 375 mShutterButton.setOnShutterButtonListener(this); 376 mShutterButton.setVisibility(View.VISIBLE); 377 378 // Initialize focus UI. 379 mPreviewFrame = findViewById(R.id.camera_preview); 380 mPreviewFrame.setOnTouchListener(this); 381 mPreviewBorder = findViewById(R.id.preview_border); 382 mFocusIndicator = (RotateLayout) findViewById(R.id.focus_indicator_rotate_layout); 383 mFocusManager.initialize(mFocusIndicator, mPreviewFrame, mFaceView, this); 384 mFocusManager.initializeToneGenerator(); 385 initializeScreenBrightness(); 386 installIntentFilter(); 387 initializeZoom(); 388 // Show the tap to focus toast if this is the first start. 389 if (mFocusAreaSupported && 390 mPreferences.getBoolean(CameraSettings.KEY_TAP_TO_FOCUS_PROMPT_SHOWN, true)) { 391 // Delay the toast for one second to wait for orientation. 392 mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000); 393 } 394 395 mFirstTimeInitialized = true; 396 addIdleHandler(); 397 } 398 399 private void addIdleHandler() { 400 MessageQueue queue = Looper.myQueue(); 401 queue.addIdleHandler(new MessageQueue.IdleHandler() { 402 public boolean queueIdle() { 403 Storage.ensureOSXCompatible(); 404 return false; 405 } 406 }); 407 } 408 409 private void initThumbnailButton() { 410 // Load the thumbnail from the disk. 411 mThumbnail = Thumbnail.loadFrom(new File(getFilesDir(), LAST_THUMB_FILENAME)); 412 updateThumbnailButton(); 413 } 414 415 private void updateThumbnailButton() { 416 // Update last image if URI is invalid and the storage is ready. 417 if ((mThumbnail == null || !Util.isUriValid(mThumbnail.getUri(), mContentResolver)) 418 && mPicturesRemaining >= 0) { 419 mThumbnail = Thumbnail.getLastImageThumbnail(mContentResolver); 420 } 421 if (mThumbnail != null) { 422 mThumbnailView.setBitmap(mThumbnail.getBitmap()); 423 } else { 424 mThumbnailView.setBitmap(null); 425 } 426 } 427 428 // If the activity is paused and resumed, this method will be called in 429 // onResume. 430 private void initializeSecondTime() { 431 // Start orientation listener as soon as possible because it takes 432 // some time to get first orientation. 433 mOrientationListener.enable(); 434 435 // Start location update if needed. 436 boolean recordLocation = RecordLocationPreference.get( 437 mPreferences, getContentResolver()); 438 mLocationManager.recordLocation(recordLocation); 439 440 installIntentFilter(); 441 mFocusManager.initializeToneGenerator(); 442 initializeZoom(); 443 keepMediaProviderInstance(); 444 checkStorage(); 445 446 if (!mIsImageCaptureIntent) { 447 updateThumbnailButton(); 448 mModePicker.setCurrentMode(ModePicker.MODE_CAMERA); 449 } 450 } 451 452 private class ZoomChangeListener implements ZoomControl.OnZoomChangedListener { 453 // only for immediate zoom 454 @Override 455 public void onZoomValueChanged(int index) { 456 Camera.this.onZoomValueChanged(index); 457 } 458 459 // only for smooth zoom 460 @Override 461 public void onZoomStateChanged(int state) { 462 if (mPausing) return; 463 464 Log.v(TAG, "zoom picker state=" + state); 465 if (state == ZoomControl.ZOOM_IN) { 466 Camera.this.onZoomValueChanged(mZoomMax); 467 } else if (state == ZoomControl.ZOOM_OUT) { 468 Camera.this.onZoomValueChanged(0); 469 } else { 470 mTargetZoomValue = -1; 471 if (mZoomState == ZOOM_START) { 472 mZoomState = ZOOM_STOPPING; 473 mCameraDevice.stopSmoothZoom(); 474 } 475 } 476 } 477 } 478 479 private void initializeZoom() { 480 if (!mParameters.isZoomSupported()) return; 481 mZoomMax = mParameters.getMaxZoom(); 482 mSmoothZoomSupported = mParameters.isSmoothZoomSupported(); 483 mZoomControl.setZoomMax(mZoomMax); 484 mZoomControl.setZoomIndex(mParameters.getZoom()); 485 mZoomControl.setSmoothZoomSupported(mSmoothZoomSupported); 486 mZoomControl.setOnZoomChangeListener(new ZoomChangeListener()); 487 mCameraDevice.setZoomChangeListener(mZoomListener); 488 } 489 490 private void onZoomValueChanged(int index) { 491 // Not useful to change zoom value when the activity is paused. 492 if (mPausing) return; 493 494 if (mSmoothZoomSupported) { 495 if (mTargetZoomValue != index && mZoomState != ZOOM_STOPPED) { 496 mTargetZoomValue = index; 497 if (mZoomState == ZOOM_START) { 498 mZoomState = ZOOM_STOPPING; 499 mCameraDevice.stopSmoothZoom(); 500 } 501 } else if (mZoomState == ZOOM_STOPPED && mZoomValue != index) { 502 mTargetZoomValue = index; 503 mCameraDevice.startSmoothZoom(index); 504 mZoomState = ZOOM_START; 505 } 506 } else { 507 mZoomValue = index; 508 setCameraParametersWhenIdle(UPDATE_PARAM_ZOOM); 509 } 510 } 511 512 @Override 513 public void startFaceDetection() { 514 if (mParameters.getMaxNumDetectedFaces() > 0) { 515 mFaceView = (FaceView) findViewById(R.id.face_view); 516 mFaceView.clear(); 517 mFaceView.setVisibility(View.VISIBLE); 518 mFaceView.setDisplayOrientation(mDisplayOrientation); 519 CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; 520 mFaceView.setMirror(info.facing == CameraInfo.CAMERA_FACING_FRONT); 521 mFaceView.resume(); 522 mCameraDevice.setFaceDetectionListener(this); 523 mCameraDevice.startFaceDetection(); 524 } 525 } 526 527 @Override 528 public void stopFaceDetection() { 529 if (mParameters.getMaxNumDetectedFaces() > 0) { 530 mCameraDevice.setFaceDetectionListener(null); 531 mCameraDevice.stopFaceDetection(); 532 if (mFaceView != null) mFaceView.clear(); 533 } 534 } 535 536 private class PopupGestureListener 537 extends GestureDetector.SimpleOnGestureListener { 538 @Override 539 public boolean onDown(MotionEvent e) { 540 // Check if the popup window is visible. 541 View popup = mIndicatorControlContainer.getActiveSettingPopup(); 542 if (popup == null) return false; 543 544 545 // Let popup window, indicator control or preview frame handle the 546 // event by themselves. Dismiss the popup window if users touch on 547 // other areas. 548 if (!Util.pointInView(e.getX(), e.getY(), popup) 549 && !Util.pointInView(e.getX(), e.getY(), mIndicatorControlContainer) 550 && !Util.pointInView(e.getX(), e.getY(), mPreviewFrame)) { 551 mIndicatorControlContainer.dismissSettingPopup(); 552 // Let event fall through. 553 } 554 return false; 555 } 556 } 557 558 @Override 559 public boolean dispatchTouchEvent(MotionEvent m) { 560 // Check if the popup window should be dismissed first. 561 if (mPopupGestureDetector != null && mPopupGestureDetector.onTouchEvent(m)) { 562 return true; 563 } 564 565 return super.dispatchTouchEvent(m); 566 } 567 568 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 569 @Override 570 public void onReceive(Context context, Intent intent) { 571 String action = intent.getAction(); 572 if (action.equals(Intent.ACTION_MEDIA_MOUNTED) 573 || action.equals(Intent.ACTION_MEDIA_UNMOUNTED) 574 || action.equals(Intent.ACTION_MEDIA_CHECKING)) { 575 checkStorage(); 576 } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) { 577 checkStorage(); 578 if (!mIsImageCaptureIntent) { 579 updateThumbnailButton(); 580 } 581 } 582 } 583 }; 584 585 private void initOnScreenIndicator() { 586 mGpsNoSignalIndicator = findViewById(R.id.onscreen_gps_indicator_no_signal); 587 mGpsHasSignalIndicator = findViewById(R.id.onscreen_gps_indicator_on); 588 mExposureIndicator = (TextView) findViewById(R.id.onscreen_exposure_indicator); 589 } 590 591 @Override 592 public void showGpsOnScreenIndicator(boolean hasSignal) { 593 if (hasSignal) { 594 if (mGpsNoSignalIndicator != null) { 595 mGpsNoSignalIndicator.setVisibility(View.GONE); 596 } 597 if (mGpsHasSignalIndicator != null) { 598 mGpsHasSignalIndicator.setVisibility(View.VISIBLE); 599 } 600 } else { 601 if (mGpsNoSignalIndicator != null) { 602 mGpsNoSignalIndicator.setVisibility(View.VISIBLE); 603 } 604 if (mGpsHasSignalIndicator != null) { 605 mGpsHasSignalIndicator.setVisibility(View.GONE); 606 } 607 } 608 } 609 610 @Override 611 public void hideGpsOnScreenIndicator() { 612 if (mGpsNoSignalIndicator != null) mGpsNoSignalIndicator.setVisibility(View.GONE); 613 if (mGpsHasSignalIndicator != null) mGpsHasSignalIndicator.setVisibility(View.GONE); 614 } 615 616 private void updateExposureOnScreenIndicator(int value) { 617 if (mExposureIndicator == null) return; 618 619 if (value == 0) { 620 mExposureIndicator.setText(""); 621 mExposureIndicator.setVisibility(View.GONE); 622 } else { 623 float step = mParameters.getExposureCompensationStep(); 624 mFormatterArgs[0] = value * step; 625 mBuilder.delete(0, mBuilder.length()); 626 mFormatter.format("%+1.1f", mFormatterArgs); 627 String exposure = mFormatter.toString(); 628 mExposureIndicator.setText(exposure); 629 mExposureIndicator.setVisibility(View.VISIBLE); 630 } 631 } 632 633 private final class ShutterCallback 634 implements android.hardware.Camera.ShutterCallback { 635 public void onShutter() { 636 mShutterCallbackTime = System.currentTimeMillis(); 637 mShutterLag = mShutterCallbackTime - mCaptureStartTime; 638 Log.v(TAG, "mShutterLag = " + mShutterLag + "ms"); 639 mFocusManager.onShutter(); 640 } 641 } 642 643 private final class PostViewPictureCallback implements PictureCallback { 644 public void onPictureTaken( 645 byte [] data, android.hardware.Camera camera) { 646 mPostViewPictureCallbackTime = System.currentTimeMillis(); 647 Log.v(TAG, "mShutterToPostViewCallbackTime = " 648 + (mPostViewPictureCallbackTime - mShutterCallbackTime) 649 + "ms"); 650 } 651 } 652 653 private final class RawPictureCallback implements PictureCallback { 654 public void onPictureTaken( 655 byte [] rawData, android.hardware.Camera camera) { 656 mRawPictureCallbackTime = System.currentTimeMillis(); 657 Log.v(TAG, "mShutterToRawCallbackTime = " 658 + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms"); 659 } 660 } 661 662 private final class JpegPictureCallback implements PictureCallback { 663 Location mLocation; 664 665 public JpegPictureCallback(Location loc) { 666 mLocation = loc; 667 } 668 669 public void onPictureTaken( 670 final byte [] jpegData, final android.hardware.Camera camera) { 671 if (mPausing) { 672 return; 673 } 674 675 mJpegPictureCallbackTime = System.currentTimeMillis(); 676 // If postview callback has arrived, the captured image is displayed 677 // in postview callback. If not, the captured image is displayed in 678 // raw picture callback. 679 if (mPostViewPictureCallbackTime != 0) { 680 mShutterToPictureDisplayedTime = 681 mPostViewPictureCallbackTime - mShutterCallbackTime; 682 mPictureDisplayedToJpegCallbackTime = 683 mJpegPictureCallbackTime - mPostViewPictureCallbackTime; 684 } else { 685 mShutterToPictureDisplayedTime = 686 mRawPictureCallbackTime - mShutterCallbackTime; 687 mPictureDisplayedToJpegCallbackTime = 688 mJpegPictureCallbackTime - mRawPictureCallbackTime; 689 } 690 Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = " 691 + mPictureDisplayedToJpegCallbackTime + "ms"); 692 693 if (!mIsImageCaptureIntent) { 694 enableCameraControls(true); 695 696 // We want to show the taken picture for a while, so we wait 697 // for at least 0.5 second before restarting the preview. 698 long delay = 500 - mPictureDisplayedToJpegCallbackTime; 699 if (delay < 0) { 700 startPreview(); 701 } else { 702 mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW, delay); 703 } 704 } 705 706 if (!mIsImageCaptureIntent) { 707 storeImage(jpegData, mLocation); 708 } else { 709 mJpegImageData = jpegData; 710 if (!mQuickCapture) { 711 showPostCaptureAlert(); 712 } else { 713 doAttach(); 714 } 715 } 716 717 // Check this in advance of each shot so we don't add to shutter 718 // latency. It's true that someone else could write to the SD card in 719 // the mean time and fill it, but that could have happened between the 720 // shutter press and saving the JPEG too. 721 checkStorage(); 722 723 if (!mHandler.hasMessages(RESTART_PREVIEW)) { 724 long now = System.currentTimeMillis(); 725 mJpegCallbackFinishTime = now - mJpegPictureCallbackTime; 726 Log.v(TAG, "mJpegCallbackFinishTime = " 727 + mJpegCallbackFinishTime + "ms"); 728 mJpegPictureCallbackTime = 0; 729 } 730 } 731 } 732 733 private final class AutoFocusCallback 734 implements android.hardware.Camera.AutoFocusCallback { 735 public void onAutoFocus( 736 boolean focused, android.hardware.Camera camera) { 737 if (mPausing) return; 738 739 mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime; 740 Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms"); 741 mFocusManager.onAutoFocus(focused); 742 // If focus completes and the snapshot is not started, enable the 743 // controls. 744 if (mFocusManager.isFocusCompleted()) { 745 enableCameraControls(true); 746 } 747 } 748 } 749 750 private final class ZoomListener 751 implements android.hardware.Camera.OnZoomChangeListener { 752 @Override 753 public void onZoomChange( 754 int value, boolean stopped, android.hardware.Camera camera) { 755 Log.v(TAG, "Zoom changed: value=" + value + ". stopped="+ stopped); 756 mZoomValue = value; 757 758 // Update the UI when we get zoom value. 759 mZoomControl.setZoomIndex(value); 760 761 // Keep mParameters up to date. We do not getParameter again in 762 // takePicture. If we do not do this, wrong zoom value will be set. 763 mParameters.setZoom(value); 764 765 if (stopped && mZoomState != ZOOM_STOPPED) { 766 if (mTargetZoomValue != -1 && value != mTargetZoomValue) { 767 mCameraDevice.startSmoothZoom(mTargetZoomValue); 768 mZoomState = ZOOM_START; 769 } else { 770 mZoomState = ZOOM_STOPPED; 771 } 772 } 773 } 774 } 775 776 private void storeImage(final byte[] data, Location loc) { 777 long dateTaken = System.currentTimeMillis(); 778 String title = Util.createJpegName(dateTaken); 779 int orientation = Exif.getOrientation(data); 780 Uri uri = Storage.addImage(mContentResolver, title, dateTaken, 781 loc, orientation, data); 782 if (uri != null) { 783 // Create a thumbnail whose width is equal or bigger than that of the preview. 784 int ratio = (int) Math.ceil((double) mParameters.getPictureSize().width 785 / mPreviewFrameLayout.getWidth()); 786 int inSampleSize = Integer.highestOneBit(ratio); 787 mThumbnail = Thumbnail.createThumbnail(data, orientation, inSampleSize, uri); 788 if (mThumbnail != null) { 789 mThumbnailView.setBitmap(mThumbnail.getBitmap()); 790 } 791 Util.broadcastNewPicture(this, uri); 792 } 793 } 794 795 @Override 796 public boolean capture() { 797 // If we are already in the middle of taking a snapshot then ignore. 798 if (mCameraState == SNAPSHOT_IN_PROGRESS || mCameraDevice == null) { 799 return false; 800 } 801 mCaptureStartTime = System.currentTimeMillis(); 802 mPostViewPictureCallbackTime = 0; 803 enableCameraControls(false); 804 mJpegImageData = null; 805 806 // Set rotation and gps data. 807 Util.setRotationParameter(mParameters, mCameraId, mOrientation); 808 Location loc = mLocationManager.getCurrentLocation(); 809 Util.setGpsParameters(mParameters, loc); 810 mCameraDevice.setParameters(mParameters); 811 812 mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback, 813 mPostViewPictureCallback, new JpegPictureCallback(loc)); 814 mCameraState = SNAPSHOT_IN_PROGRESS; 815 return true; 816 } 817 818 @Override 819 public void setFocusParameters() { 820 setCameraParameters(UPDATE_PARAM_PREFERENCE); 821 } 822 823 private boolean saveDataToFile(String filePath, byte[] data) { 824 FileOutputStream f = null; 825 try { 826 f = new FileOutputStream(filePath); 827 f.write(data); 828 } catch (IOException e) { 829 return false; 830 } finally { 831 Util.closeSilently(f); 832 } 833 return true; 834 } 835 836 @Override 837 public void onCreate(Bundle icicle) { 838 super.onCreate(icicle); 839 840 mIsImageCaptureIntent = isImageCaptureIntent(); 841 setContentView(R.layout.camera); 842 if (mIsImageCaptureIntent) { 843 findViewById(R.id.btn_cancel).setVisibility(View.VISIBLE); 844 } else { 845 mThumbnailView = (RotateImageView) findViewById(R.id.thumbnail); 846 mThumbnailView.setVisibility(View.VISIBLE); 847 } 848 849 mPreferences = new ComboPreferences(this); 850 CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal()); 851 mFocusManager = new FocusManager(mPreferences, 852 getString(R.string.pref_camera_focusmode_default)); 853 854 mCameraId = CameraSettings.readPreferredCameraId(mPreferences); 855 856 // Testing purpose. Launch a specific camera through the intent extras. 857 int intentCameraId = Util.getCameraFacingIntentExtras(this); 858 if (intentCameraId != -1) { 859 mCameraId = intentCameraId; 860 } 861 862 mPreferences.setLocalId(this, mCameraId); 863 CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); 864 865 mNumberOfCameras = CameraHolder.instance().getNumberOfCameras(); 866 mQuickCapture = getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false); 867 868 // we need to reset exposure for the preview 869 resetExposureCompensation(); 870 871 /* 872 * To reduce startup time, we start the preview in another thread. 873 * We make sure the preview is started at the end of onCreate. 874 */ 875 Thread startPreviewThread = new Thread(new Runnable() { 876 public void run() { 877 try { 878 mCameraDevice = Util.openCamera(Camera.this, mCameraId); 879 initializeCapabilities(); 880 startPreview(); 881 } catch (CameraHardwareException e) { 882 mOpenCameraFail = true; 883 } catch (CameraDisabledException e) { 884 mCameraDisabled = true; 885 } 886 } 887 }); 888 startPreviewThread.start(); 889 890 // don't set mSurfaceHolder here. We have it set ONLY within 891 // surfaceChanged / surfaceDestroyed, other parts of the code 892 // assume that when it is set, the surface is also set. 893 SurfaceView preview = (SurfaceView) findViewById(R.id.camera_preview); 894 SurfaceHolder holder = preview.getHolder(); 895 holder.addCallback(this); 896 holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 897 898 if (mIsImageCaptureIntent) { 899 setupCaptureParams(); 900 } else { 901 mModePicker = (ModePicker) findViewById(R.id.mode_picker); 902 mModePicker.setVisibility(View.VISIBLE); 903 mModePicker.setOnModeChangeListener(this); 904 mModePicker.setCurrentMode(ModePicker.MODE_CAMERA); 905 } 906 907 mZoomControl = (ZoomControl) findViewById(R.id.zoom_control); 908 mLocationManager = new LocationManager(this, this); 909 910 // Make sure preview is started. 911 try { 912 startPreviewThread.join(); 913 if (mOpenCameraFail) { 914 Util.showErrorAndFinish(this, R.string.cannot_connect_camera); 915 return; 916 } else if (mCameraDisabled) { 917 Util.showErrorAndFinish(this, R.string.camera_disabled); 918 return; 919 } 920 } catch (InterruptedException ex) { 921 // ignore 922 } 923 924 mBackCameraId = CameraHolder.instance().getBackCameraId(); 925 mFrontCameraId = CameraHolder.instance().getFrontCameraId(); 926 927 // Do this after starting preview because it depends on camera 928 // parameters. 929 initializeIndicatorControl(); 930 } 931 932 private void overrideCameraSettings(final String flashMode, 933 final String whiteBalance, final String focusMode) { 934 if (mIndicatorControlContainer != null) { 935 mIndicatorControlContainer.overrideSettings( 936 CameraSettings.KEY_FLASH_MODE, flashMode, 937 CameraSettings.KEY_WHITE_BALANCE, whiteBalance, 938 CameraSettings.KEY_FOCUS_MODE, focusMode); 939 } 940 } 941 942 private void updateSceneModeUI() { 943 // If scene mode is set, we cannot set flash mode, white balance, and 944 // focus mode, instead, we read it from driver 945 if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) { 946 overrideCameraSettings(mParameters.getFlashMode(), 947 mParameters.getWhiteBalance(), mParameters.getFocusMode()); 948 } else { 949 overrideCameraSettings(null, null, null); 950 } 951 } 952 953 private void loadCameraPreferences() { 954 CameraSettings settings = new CameraSettings(this, mInitialParams, 955 mCameraId, CameraHolder.instance().getCameraInfo()); 956 mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences); 957 } 958 959 private void initializeIndicatorControl() { 960 // setting the indicator buttons. 961 mIndicatorControlContainer = 962 (IndicatorControlContainer) findViewById(R.id.indicator_control); 963 if (mIndicatorControlContainer == null) return; 964 loadCameraPreferences(); 965 final String[] SETTING_KEYS = { 966 CameraSettings.KEY_WHITE_BALANCE, 967 CameraSettings.KEY_SCENE_MODE}; 968 final String[] OTHER_SETTING_KEYS = { 969 CameraSettings.KEY_RECORD_LOCATION, 970 CameraSettings.KEY_FOCUS_MODE, 971 CameraSettings.KEY_EXPOSURE, 972 CameraSettings.KEY_PICTURE_SIZE}; 973 974 CameraPicker.setImageResourceId(R.drawable.ic_switch_photo_facing_holo_light); 975 mIndicatorControlContainer.initialize(this, mPreferenceGroup, 976 CameraSettings.KEY_FLASH_MODE, mParameters.isZoomSupported(), 977 SETTING_KEYS, OTHER_SETTING_KEYS); 978 mIndicatorControlContainer.setListener(this); 979 } 980 981 private boolean collapseCameraControls() { 982 if ((mIndicatorControlContainer != null) 983 && mIndicatorControlContainer.dismissSettingPopup()) { 984 return true; 985 } 986 return false; 987 } 988 989 private void enableCameraControls(boolean enable) { 990 if (mIndicatorControlContainer != null) { 991 mIndicatorControlContainer.setEnabled(enable); 992 } 993 if (mModePicker != null) mModePicker.setEnabled(enable); 994 if (mZoomControl != null) mZoomControl.setEnabled(enable); 995 } 996 997 public static int roundOrientation(int orientation) { 998 return ((orientation + 45) / 90 * 90) % 360; 999 } 1000 1001 private class MyOrientationEventListener 1002 extends OrientationEventListener { 1003 public MyOrientationEventListener(Context context) { 1004 super(context); 1005 } 1006 1007 @Override 1008 public void onOrientationChanged(int orientation) { 1009 // We keep the last known orientation. So if the user first orient 1010 // the camera then point the camera to floor or sky, we still have 1011 // the correct orientation. 1012 if (orientation == ORIENTATION_UNKNOWN) return; 1013 mOrientation = roundOrientation(orientation); 1014 // When the screen is unlocked, display rotation may change. Always 1015 // calculate the up-to-date orientationCompensation. 1016 int orientationCompensation = mOrientation 1017 + Util.getDisplayRotation(Camera.this); 1018 if (mOrientationCompensation != orientationCompensation) { 1019 mOrientationCompensation = orientationCompensation; 1020 setOrientationIndicator(mOrientationCompensation); 1021 } 1022 1023 // Show the toast after getting the first orientation changed. 1024 if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) { 1025 mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST); 1026 showTapToFocusToast(); 1027 } 1028 } 1029 } 1030 1031 private void setOrientationIndicator(int degree) { 1032 if (mThumbnailView != null) mThumbnailView.setDegree(degree); 1033 if (mModePicker != null) mModePicker.setDegree(degree); 1034 if (mSharePopup != null) mSharePopup.setOrientation(degree); 1035 if (mIndicatorControlContainer != null) mIndicatorControlContainer.setDegree(degree); 1036 if (mZoomControl != null) mZoomControl.setDegree(degree); 1037 if (mFocusIndicator != null) mFocusIndicator.setOrientation(degree); 1038 if (mFaceView != null) mFaceView.setOrientation(degree); 1039 } 1040 1041 @Override 1042 public void onStop() { 1043 super.onStop(); 1044 if (mMediaProviderClient != null) { 1045 mMediaProviderClient.release(); 1046 mMediaProviderClient = null; 1047 } 1048 } 1049 1050 private void checkStorage() { 1051 mPicturesRemaining = Storage.getAvailableSpace(); 1052 if (mPicturesRemaining > 0) { 1053 mPicturesRemaining /= 1500000; 1054 } 1055 updateStorageHint(); 1056 } 1057 1058 @OnClickAttr 1059 public void onThumbnailClicked(View v) { 1060 if (isCameraIdle() && mThumbnail != null) { 1061 showSharePopup(); 1062 } 1063 } 1064 1065 @OnClickAttr 1066 public void onRetakeButtonClicked(View v) { 1067 hidePostCaptureAlert(); 1068 startPreview(); 1069 } 1070 1071 @OnClickAttr 1072 public void onDoneButtonClicked(View v) { 1073 doAttach(); 1074 } 1075 1076 @OnClickAttr 1077 public void onCancelButtonClicked(View v) { 1078 doCancel(); 1079 } 1080 1081 private void doAttach() { 1082 if (mPausing) { 1083 return; 1084 } 1085 1086 byte[] data = mJpegImageData; 1087 1088 if (mCropValue == null) { 1089 // First handle the no crop case -- just return the value. If the 1090 // caller specifies a "save uri" then write the data to it's 1091 // stream. Otherwise, pass back a scaled down version of the bitmap 1092 // directly in the extras. 1093 if (mSaveUri != null) { 1094 OutputStream outputStream = null; 1095 try { 1096 outputStream = mContentResolver.openOutputStream(mSaveUri); 1097 outputStream.write(data); 1098 outputStream.close(); 1099 1100 setResultEx(RESULT_OK); 1101 finish(); 1102 } catch (IOException ex) { 1103 // ignore exception 1104 } finally { 1105 Util.closeSilently(outputStream); 1106 } 1107 } else { 1108 int orientation = Exif.getOrientation(data); 1109 Bitmap bitmap = Util.makeBitmap(data, 50 * 1024); 1110 bitmap = Util.rotate(bitmap, orientation); 1111 setResultEx(RESULT_OK, 1112 new Intent("inline-data").putExtra("data", bitmap)); 1113 finish(); 1114 } 1115 } else { 1116 // Save the image to a temp file and invoke the cropper 1117 Uri tempUri = null; 1118 FileOutputStream tempStream = null; 1119 try { 1120 File path = getFileStreamPath(sTempCropFilename); 1121 path.delete(); 1122 tempStream = openFileOutput(sTempCropFilename, 0); 1123 tempStream.write(data); 1124 tempStream.close(); 1125 tempUri = Uri.fromFile(path); 1126 } catch (FileNotFoundException ex) { 1127 setResultEx(Activity.RESULT_CANCELED); 1128 finish(); 1129 return; 1130 } catch (IOException ex) { 1131 setResultEx(Activity.RESULT_CANCELED); 1132 finish(); 1133 return; 1134 } finally { 1135 Util.closeSilently(tempStream); 1136 } 1137 1138 Bundle newExtras = new Bundle(); 1139 if (mCropValue.equals("circle")) { 1140 newExtras.putString("circleCrop", "true"); 1141 } 1142 if (mSaveUri != null) { 1143 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri); 1144 } else { 1145 newExtras.putBoolean("return-data", true); 1146 } 1147 1148 Intent cropIntent = new Intent("com.android.camera.action.CROP"); 1149 1150 cropIntent.setData(tempUri); 1151 cropIntent.putExtras(newExtras); 1152 1153 startActivityForResult(cropIntent, CROP_MSG); 1154 } 1155 } 1156 1157 private void doCancel() { 1158 setResultEx(RESULT_CANCELED, new Intent()); 1159 finish(); 1160 } 1161 1162 public void onShutterButtonFocus(ShutterButton button, boolean pressed) { 1163 switch (button.getId()) { 1164 case R.id.shutter_button: 1165 doFocus(pressed); 1166 break; 1167 } 1168 } 1169 1170 public void onShutterButtonClick(ShutterButton button) { 1171 switch (button.getId()) { 1172 case R.id.shutter_button: 1173 doSnap(); 1174 break; 1175 } 1176 } 1177 1178 private OnScreenHint mStorageHint; 1179 1180 private void updateStorageHint() { 1181 String noStorageText = null; 1182 1183 if (mPicturesRemaining == Storage.UNAVAILABLE) { 1184 noStorageText = getString(R.string.no_storage); 1185 } else if (mPicturesRemaining == Storage.PREPARING) { 1186 noStorageText = getString(R.string.preparing_sd); 1187 } else if (mPicturesRemaining == Storage.UNKNOWN_SIZE) { 1188 noStorageText = getString(R.string.access_sd_fail); 1189 } else if (mPicturesRemaining < 1L) { 1190 noStorageText = getString(R.string.not_enough_space); 1191 } 1192 1193 if (noStorageText != null) { 1194 if (mStorageHint == null) { 1195 mStorageHint = OnScreenHint.makeText(this, noStorageText); 1196 } else { 1197 mStorageHint.setText(noStorageText); 1198 } 1199 mStorageHint.show(); 1200 } else if (mStorageHint != null) { 1201 mStorageHint.cancel(); 1202 mStorageHint = null; 1203 } 1204 } 1205 1206 private void installIntentFilter() { 1207 // install an intent filter to receive SD card related events. 1208 IntentFilter intentFilter = 1209 new IntentFilter(Intent.ACTION_MEDIA_MOUNTED); 1210 intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); 1211 intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED); 1212 intentFilter.addAction(Intent.ACTION_MEDIA_CHECKING); 1213 intentFilter.addDataScheme("file"); 1214 registerReceiver(mReceiver, intentFilter); 1215 mDidRegister = true; 1216 } 1217 1218 private void initializeScreenBrightness() { 1219 Window win = getWindow(); 1220 // Overright the brightness settings if it is automatic 1221 int mode = Settings.System.getInt( 1222 getContentResolver(), 1223 Settings.System.SCREEN_BRIGHTNESS_MODE, 1224 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); 1225 if (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) { 1226 WindowManager.LayoutParams winParams = win.getAttributes(); 1227 winParams.screenBrightness = DEFAULT_CAMERA_BRIGHTNESS; 1228 win.setAttributes(winParams); 1229 } 1230 } 1231 1232 @Override 1233 protected void onResume() { 1234 super.onResume(); 1235 mPausing = false; 1236 if (mOpenCameraFail || mCameraDisabled) return; 1237 1238 mJpegPictureCallbackTime = 0; 1239 mZoomValue = 0; 1240 1241 // Start the preview if it is not started. 1242 if (mCameraState == PREVIEW_STOPPED) { 1243 try { 1244 mCameraDevice = Util.openCamera(this, mCameraId); 1245 initializeCapabilities(); 1246 resetExposureCompensation(); 1247 startPreview(); 1248 } catch(CameraHardwareException e) { 1249 Util.showErrorAndFinish(this, R.string.cannot_connect_camera); 1250 return; 1251 } catch(CameraDisabledException e) { 1252 Util.showErrorAndFinish(this, R.string.camera_disabled); 1253 return; 1254 } 1255 } 1256 1257 if (mSurfaceHolder != null) { 1258 // If first time initialization is not finished, put it in the 1259 // message queue. 1260 if (!mFirstTimeInitialized) { 1261 mHandler.sendEmptyMessage(FIRST_TIME_INIT); 1262 } else { 1263 initializeSecondTime(); 1264 } 1265 } 1266 keepScreenOnAwhile(); 1267 1268 if (mCameraState == IDLE) { 1269 mOnResumeTime = SystemClock.uptimeMillis(); 1270 mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100); 1271 } 1272 } 1273 1274 @Override 1275 protected void onPause() { 1276 mPausing = true; 1277 stopPreview(); 1278 // Close the camera now because other activities may need to use it. 1279 closeCamera(); 1280 resetScreenOn(); 1281 1282 // Clear UI. 1283 collapseCameraControls(); 1284 if (mSharePopup != null) mSharePopup.dismiss(); 1285 if (mFaceView != null) mFaceView.clear(); 1286 1287 if (mFirstTimeInitialized) { 1288 mOrientationListener.disable(); 1289 if (!mIsImageCaptureIntent) { 1290 if (mThumbnail != null) { 1291 mThumbnail.saveTo(new File(getFilesDir(), LAST_THUMB_FILENAME)); 1292 } 1293 } 1294 hidePostCaptureAlert(); 1295 } 1296 1297 if (mDidRegister) { 1298 unregisterReceiver(mReceiver); 1299 mDidRegister = false; 1300 } 1301 mLocationManager.recordLocation(false); 1302 updateExposureOnScreenIndicator(0); 1303 1304 mFocusManager.releaseToneGenerator(); 1305 1306 if (mStorageHint != null) { 1307 mStorageHint.cancel(); 1308 mStorageHint = null; 1309 } 1310 1311 // If we are in an image capture intent and has taken 1312 // a picture, we just clear it in onPause. 1313 mJpegImageData = null; 1314 1315 // Remove the messages in the event queue. 1316 mHandler.removeMessages(RESTART_PREVIEW); 1317 mHandler.removeMessages(FIRST_TIME_INIT); 1318 mHandler.removeMessages(CHECK_DISPLAY_ROTATION); 1319 mFocusManager.removeMessages(); 1320 1321 super.onPause(); 1322 } 1323 1324 @Override 1325 protected void onActivityResult( 1326 int requestCode, int resultCode, Intent data) { 1327 switch (requestCode) { 1328 case CROP_MSG: { 1329 Intent intent = new Intent(); 1330 if (data != null) { 1331 Bundle extras = data.getExtras(); 1332 if (extras != null) { 1333 intent.putExtras(extras); 1334 } 1335 } 1336 setResultEx(resultCode, intent); 1337 finish(); 1338 1339 File path = getFileStreamPath(sTempCropFilename); 1340 path.delete(); 1341 1342 break; 1343 } 1344 } 1345 } 1346 1347 private boolean canTakePicture() { 1348 return isCameraIdle() && (mPicturesRemaining > 0); 1349 } 1350 1351 @Override 1352 public void autoFocus() { 1353 mFocusStartTime = System.currentTimeMillis(); 1354 mCameraDevice.autoFocus(mAutoFocusCallback); 1355 mCameraState = FOCUSING; 1356 enableCameraControls(false); 1357 } 1358 1359 @Override 1360 public void cancelAutoFocus() { 1361 mCameraDevice.cancelAutoFocus(); 1362 mCameraState = IDLE; 1363 enableCameraControls(true); 1364 setCameraParameters(UPDATE_PARAM_PREFERENCE); 1365 } 1366 1367 // Preview area is touched. Handle touch focus. 1368 @Override 1369 public boolean onTouch(View v, MotionEvent e) { 1370 if (mPausing || !mFirstTimeInitialized || mCameraState == SNAPSHOT_IN_PROGRESS) { 1371 return false; 1372 } 1373 1374 // Do not trigger touch focus if popup window is opened. 1375 if (collapseCameraControls()) return false; 1376 1377 // Check if metering area or focus area is supported. 1378 if (!mFocusAreaSupported && !mMeteringAreaSupported) return false; 1379 1380 return mFocusManager.onTouch(e); 1381 } 1382 1383 @Override 1384 public void onBackPressed() { 1385 if (!isCameraIdle()) { 1386 // ignore backs while we're taking a picture 1387 return; 1388 } else if (!collapseCameraControls()) { 1389 super.onBackPressed(); 1390 } 1391 } 1392 1393 @Override 1394 public boolean onKeyDown(int keyCode, KeyEvent event) { 1395 switch (keyCode) { 1396 case KeyEvent.KEYCODE_FOCUS: 1397 if (mFirstTimeInitialized && event.getRepeatCount() == 0) { 1398 doFocus(true); 1399 } 1400 return true; 1401 case KeyEvent.KEYCODE_CAMERA: 1402 if (mFirstTimeInitialized && event.getRepeatCount() == 0) { 1403 doSnap(); 1404 } 1405 return true; 1406 case KeyEvent.KEYCODE_DPAD_CENTER: 1407 // If we get a dpad center event without any focused view, move 1408 // the focus to the shutter button and press it. 1409 if (mFirstTimeInitialized && event.getRepeatCount() == 0) { 1410 // Start auto-focus immediately to reduce shutter lag. After 1411 // the shutter button gets the focus, doFocus() will be 1412 // called again but it is fine. 1413 if (collapseCameraControls()) return true; 1414 doFocus(true); 1415 if (mShutterButton.isInTouchMode()) { 1416 mShutterButton.requestFocusFromTouch(); 1417 } else { 1418 mShutterButton.requestFocus(); 1419 } 1420 mShutterButton.setPressed(true); 1421 } 1422 return true; 1423 } 1424 1425 return super.onKeyDown(keyCode, event); 1426 } 1427 1428 @Override 1429 public boolean onKeyUp(int keyCode, KeyEvent event) { 1430 switch (keyCode) { 1431 case KeyEvent.KEYCODE_FOCUS: 1432 if (mFirstTimeInitialized) { 1433 doFocus(false); 1434 } 1435 return true; 1436 } 1437 return super.onKeyUp(keyCode, event); 1438 } 1439 1440 private void doSnap() { 1441 if (mPausing || collapseCameraControls()) return; 1442 1443 Log.v(TAG, "doSnap: mCameraState=" + mCameraState); 1444 mFocusManager.doSnap(); 1445 } 1446 1447 private void doFocus(boolean pressed) { 1448 if (mPausing || collapseCameraControls()) return; 1449 1450 // Do not do focus if there is not enough storage. 1451 if (pressed && !canTakePicture()) return; 1452 1453 mFocusManager.doFocus(pressed); 1454 } 1455 1456 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 1457 // Make sure we have a surface in the holder before proceeding. 1458 if (holder.getSurface() == null) { 1459 Log.d(TAG, "holder.getSurface() == null"); 1460 return; 1461 } 1462 1463 Log.v(TAG, "surfaceChanged. w=" + w + ". h=" + h); 1464 1465 // We need to save the holder for later use, even when the mCameraDevice 1466 // is null. This could happen if onResume() is invoked after this 1467 // function. 1468 mSurfaceHolder = holder; 1469 1470 // The mCameraDevice will be null if it fails to connect to the camera 1471 // hardware. In this case we will show a dialog and then finish the 1472 // activity, so it's OK to ignore it. 1473 if (mCameraDevice == null) return; 1474 1475 // Sometimes surfaceChanged is called after onPause or before onResume. 1476 // Ignore it. 1477 if (mPausing || isFinishing()) return; 1478 1479 // Set preview display if the surface is being created. Preview was 1480 // already started. Also restart the preview if display rotation has 1481 // changed. Sometimes this happens when the device is held in portrait 1482 // and camera app is opened. Rotation animation takes some time and 1483 // display rotation in onCreate may not be what we want. 1484 if (mCameraState != PREVIEW_STOPPED 1485 && (Util.getDisplayRotation(this) == mDisplayRotation) 1486 && holder.isCreating()) { 1487 // Set preview display if the surface is being created and preview 1488 // was already started. That means preview display was set to null 1489 // and we need to set it now. 1490 setPreviewDisplay(holder); 1491 } else { 1492 // 1. Restart the preview if the size of surface was changed. The 1493 // framework may not support changing preview display on the fly. 1494 // 2. Start the preview now if surface was destroyed and preview 1495 // stopped. 1496 startPreview(); 1497 } 1498 1499 // If first time initialization is not finished, send a message to do 1500 // it later. We want to finish surfaceChanged as soon as possible to let 1501 // user see preview first. 1502 if (!mFirstTimeInitialized) { 1503 mHandler.sendEmptyMessage(FIRST_TIME_INIT); 1504 } else { 1505 initializeSecondTime(); 1506 } 1507 } 1508 1509 public void surfaceCreated(SurfaceHolder holder) { 1510 } 1511 1512 public void surfaceDestroyed(SurfaceHolder holder) { 1513 stopPreview(); 1514 mSurfaceHolder = null; 1515 } 1516 1517 private void closeCamera() { 1518 if (mCameraDevice != null) { 1519 CameraHolder.instance().release(); 1520 mCameraDevice.setZoomChangeListener(null); 1521 mCameraDevice.setFaceDetectionListener(null); 1522 mCameraDevice = null; 1523 mCameraState = PREVIEW_STOPPED; 1524 mFocusManager.onCameraReleased(); 1525 } 1526 } 1527 1528 private void setPreviewDisplay(SurfaceHolder holder) { 1529 try { 1530 mCameraDevice.setPreviewDisplay(holder); 1531 } catch (Throwable ex) { 1532 closeCamera(); 1533 throw new RuntimeException("setPreviewDisplay failed", ex); 1534 } 1535 } 1536 1537 private void startPreview() { 1538 if (mPausing || isFinishing()) return; 1539 1540 mFocusManager.resetTouchFocus(); 1541 1542 mCameraDevice.setErrorCallback(mErrorCallback); 1543 1544 // If we're previewing already, stop the preview first (this will blank 1545 // the screen). 1546 if (mCameraState != PREVIEW_STOPPED) stopPreview(); 1547 1548 setPreviewDisplay(mSurfaceHolder); 1549 mDisplayRotation = Util.getDisplayRotation(this); 1550 mDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId); 1551 mCameraDevice.setDisplayOrientation(mDisplayOrientation); 1552 if (mFaceView != null) { 1553 mFaceView.setDisplayOrientation(mDisplayOrientation); 1554 } 1555 setCameraParameters(UPDATE_PARAM_ALL); 1556 1557 try { 1558 Log.v(TAG, "startPreview"); 1559 mCameraDevice.startPreview(); 1560 } catch (Throwable ex) { 1561 closeCamera(); 1562 throw new RuntimeException("startPreview failed", ex); 1563 } 1564 1565 startFaceDetection(); 1566 mZoomState = ZOOM_STOPPED; 1567 mCameraState = IDLE; 1568 mFocusManager.onPreviewStarted(); 1569 } 1570 1571 private void stopPreview() { 1572 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { 1573 Log.v(TAG, "stopPreview"); 1574 mCameraDevice.stopPreview(); 1575 } 1576 mCameraState = PREVIEW_STOPPED; 1577 mFocusManager.onPreviewStopped(); 1578 } 1579 1580 private static boolean isSupported(String value, List<String> supported) { 1581 return supported == null ? false : supported.indexOf(value) >= 0; 1582 } 1583 1584 private void updateCameraParametersInitialize() { 1585 // Reset preview frame rate to the maximum because it may be lowered by 1586 // video camera application. 1587 List<Integer> frameRates = mParameters.getSupportedPreviewFrameRates(); 1588 if (frameRates != null) { 1589 Integer max = Collections.max(frameRates); 1590 mParameters.setPreviewFrameRate(max); 1591 } 1592 1593 mParameters.setRecordingHint(false); 1594 } 1595 1596 private void updateCameraParametersZoom() { 1597 // Set zoom. 1598 if (mParameters.isZoomSupported()) { 1599 mParameters.setZoom(mZoomValue); 1600 } 1601 } 1602 1603 private void updateCameraParametersPreference() { 1604 if (mFocusAreaSupported) { 1605 mParameters.setFocusAreas(mFocusManager.getTapArea()); 1606 } 1607 1608 if (mMeteringAreaSupported) { 1609 // Use the same area for focus and metering. 1610 mParameters.setMeteringAreas(mFocusManager.getTapArea()); 1611 } 1612 1613 // Set picture size. 1614 String pictureSize = mPreferences.getString( 1615 CameraSettings.KEY_PICTURE_SIZE, null); 1616 if (pictureSize == null) { 1617 CameraSettings.initialCameraPictureSize(this, mParameters); 1618 } else { 1619 List<Size> supported = mParameters.getSupportedPictureSizes(); 1620 CameraSettings.setCameraPictureSize( 1621 pictureSize, supported, mParameters); 1622 } 1623 1624 // Set the preview frame aspect ratio according to the picture size. 1625 Size size = mParameters.getPictureSize(); 1626 1627 mPreviewFrameLayout = (PreviewFrameLayout) findViewById(R.id.frame_layout); 1628 mPreviewFrameLayout.setAspectRatio((double) size.width / size.height); 1629 1630 // Set a preview size that is closest to the viewfinder height and has 1631 // the right aspect ratio. 1632 List<Size> sizes = mParameters.getSupportedPreviewSizes(); 1633 Size optimalSize = Util.getOptimalPreviewSize(this, 1634 sizes, (double) size.width / size.height); 1635 Size original = mParameters.getPreviewSize(); 1636 if (!original.equals(optimalSize)) { 1637 mParameters.setPreviewSize(optimalSize.width, optimalSize.height); 1638 1639 // Zoom related settings will be changed for different preview 1640 // sizes, so set and read the parameters to get lastest values 1641 mCameraDevice.setParameters(mParameters); 1642 mParameters = mCameraDevice.getParameters(); 1643 } 1644 Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height); 1645 1646 // Since change scene mode may change supported values, 1647 // Set scene mode first, 1648 mSceneMode = mPreferences.getString( 1649 CameraSettings.KEY_SCENE_MODE, 1650 getString(R.string.pref_camera_scenemode_default)); 1651 if (isSupported(mSceneMode, mParameters.getSupportedSceneModes())) { 1652 if (!mParameters.getSceneMode().equals(mSceneMode)) { 1653 mParameters.setSceneMode(mSceneMode); 1654 mCameraDevice.setParameters(mParameters); 1655 1656 // Setting scene mode will change the settings of flash mode, 1657 // white balance, and focus mode. Here we read back the 1658 // parameters, so we can know those settings. 1659 mParameters = mCameraDevice.getParameters(); 1660 } 1661 } else { 1662 mSceneMode = mParameters.getSceneMode(); 1663 if (mSceneMode == null) { 1664 mSceneMode = Parameters.SCENE_MODE_AUTO; 1665 } 1666 } 1667 1668 // Set JPEG quality. 1669 int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId, 1670 CameraProfile.QUALITY_HIGH); 1671 mParameters.setJpegQuality(jpegQuality); 1672 1673 // For the following settings, we need to check if the settings are 1674 // still supported by latest driver, if not, ignore the settings. 1675 1676 // Set exposure compensation 1677 int value = CameraSettings.readExposure(mPreferences); 1678 int max = mParameters.getMaxExposureCompensation(); 1679 int min = mParameters.getMinExposureCompensation(); 1680 if (value >= min && value <= max) { 1681 mParameters.setExposureCompensation(value); 1682 } else { 1683 Log.w(TAG, "invalid exposure range: " + value); 1684 } 1685 1686 if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) { 1687 // Set flash mode. 1688 String flashMode = mPreferences.getString( 1689 CameraSettings.KEY_FLASH_MODE, 1690 getString(R.string.pref_camera_flashmode_default)); 1691 List<String> supportedFlash = mParameters.getSupportedFlashModes(); 1692 if (isSupported(flashMode, supportedFlash)) { 1693 mParameters.setFlashMode(flashMode); 1694 } else { 1695 flashMode = mParameters.getFlashMode(); 1696 if (flashMode == null) { 1697 flashMode = getString( 1698 R.string.pref_camera_flashmode_no_flash); 1699 } 1700 } 1701 1702 // Set white balance parameter. 1703 String whiteBalance = mPreferences.getString( 1704 CameraSettings.KEY_WHITE_BALANCE, 1705 getString(R.string.pref_camera_whitebalance_default)); 1706 if (isSupported(whiteBalance, 1707 mParameters.getSupportedWhiteBalance())) { 1708 mParameters.setWhiteBalance(whiteBalance); 1709 } else { 1710 whiteBalance = mParameters.getWhiteBalance(); 1711 if (whiteBalance == null) { 1712 whiteBalance = Parameters.WHITE_BALANCE_AUTO; 1713 } 1714 } 1715 1716 // Set focus mode. 1717 mFocusManager.overrideFocusMode(null); 1718 mParameters.setFocusMode(mFocusManager.getFocusMode()); 1719 } else { 1720 mFocusManager.overrideFocusMode(mParameters.getFocusMode()); 1721 } 1722 } 1723 1724 // We separate the parameters into several subsets, so we can update only 1725 // the subsets actually need updating. The PREFERENCE set needs extra 1726 // locking because the preference can be changed from GLThread as well. 1727 private void setCameraParameters(int updateSet) { 1728 mParameters = mCameraDevice.getParameters(); 1729 1730 if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) { 1731 updateCameraParametersInitialize(); 1732 } 1733 1734 if ((updateSet & UPDATE_PARAM_ZOOM) != 0) { 1735 updateCameraParametersZoom(); 1736 } 1737 1738 if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) { 1739 updateCameraParametersPreference(); 1740 } 1741 1742 mCameraDevice.setParameters(mParameters); 1743 } 1744 1745 // If the Camera is idle, update the parameters immediately, otherwise 1746 // accumulate them in mUpdateSet and update later. 1747 private void setCameraParametersWhenIdle(int additionalUpdateSet) { 1748 mUpdateSet |= additionalUpdateSet; 1749 if (mCameraDevice == null) { 1750 // We will update all the parameters when we open the device, so 1751 // we don't need to do anything now. 1752 mUpdateSet = 0; 1753 return; 1754 } else if (isCameraIdle()) { 1755 setCameraParameters(mUpdateSet); 1756 updateSceneModeUI(); 1757 mUpdateSet = 0; 1758 } else { 1759 if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) { 1760 mHandler.sendEmptyMessageDelayed( 1761 SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000); 1762 } 1763 } 1764 } 1765 1766 private void gotoGallery() { 1767 MenuHelper.gotoCameraImageGallery(this); 1768 } 1769 1770 private boolean isCameraIdle() { 1771 return (mCameraState == IDLE) || (mFocusManager.isFocusCompleted()); 1772 } 1773 1774 private boolean isImageCaptureIntent() { 1775 String action = getIntent().getAction(); 1776 return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)); 1777 } 1778 1779 private void setupCaptureParams() { 1780 Bundle myExtras = getIntent().getExtras(); 1781 if (myExtras != null) { 1782 mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT); 1783 mCropValue = myExtras.getString("crop"); 1784 } 1785 } 1786 1787 private void showPostCaptureAlert() { 1788 if (mIsImageCaptureIntent) { 1789 mShutterButton.setVisibility(View.GONE); 1790 mIndicatorControlContainer.setVisibility(View.GONE); 1791 1792 int[] pickIds = {R.id.btn_retake, R.id.btn_done}; 1793 for (int id : pickIds) { 1794 Util.fadeIn(findViewById(id)); 1795 } 1796 } 1797 } 1798 1799 private void hidePostCaptureAlert() { 1800 if (mIsImageCaptureIntent) { 1801 enableCameraControls(true); 1802 1803 int[] pickIds = {R.id.btn_retake, R.id.btn_done}; 1804 for (int id : pickIds) { 1805 (findViewById(id)).setVisibility(View.GONE); 1806 } 1807 1808 Util.fadeIn(mShutterButton); 1809 Util.fadeIn(mIndicatorControlContainer); 1810 } 1811 } 1812 1813 @Override 1814 public boolean onPrepareOptionsMenu(Menu menu) { 1815 super.onPrepareOptionsMenu(menu); 1816 // Only show the menu when camera is idle. 1817 for (int i = 0; i < menu.size(); i++) { 1818 menu.getItem(i).setVisible(isCameraIdle()); 1819 } 1820 1821 return true; 1822 } 1823 1824 @Override 1825 public boolean onCreateOptionsMenu(Menu menu) { 1826 super.onCreateOptionsMenu(menu); 1827 1828 if (mIsImageCaptureIntent) { 1829 // No options menu for attach mode. 1830 return false; 1831 } else { 1832 addBaseMenuItems(menu); 1833 } 1834 return true; 1835 } 1836 1837 private void addBaseMenuItems(Menu menu) { 1838 MenuHelper.addSwitchModeMenuItem(menu, ModePicker.MODE_VIDEO, new Runnable() { 1839 public void run() { 1840 switchToOtherMode(ModePicker.MODE_VIDEO); 1841 } 1842 }); 1843 MenuHelper.addSwitchModeMenuItem(menu, ModePicker.MODE_PANORAMA, new Runnable() { 1844 public void run() { 1845 switchToOtherMode(ModePicker.MODE_PANORAMA); 1846 } 1847 }); 1848 MenuItem gallery = menu.add(R.string.camera_gallery_photos_text) 1849 .setOnMenuItemClickListener(new OnMenuItemClickListener() { 1850 public boolean onMenuItemClick(MenuItem item) { 1851 gotoGallery(); 1852 return true; 1853 } 1854 }); 1855 gallery.setIcon(android.R.drawable.ic_menu_gallery); 1856 mGalleryItems.add(gallery); 1857 1858 if (mNumberOfCameras > 1) { 1859 menu.add(R.string.switch_camera_id) 1860 .setOnMenuItemClickListener(new OnMenuItemClickListener() { 1861 public boolean onMenuItemClick(MenuItem item) { 1862 CameraSettings.writePreferredCameraId(mPreferences, 1863 ((mCameraId == mFrontCameraId) 1864 ? mBackCameraId : mFrontCameraId)); 1865 onSharedPreferenceChanged(); 1866 return true; 1867 } 1868 }).setIcon(android.R.drawable.ic_menu_camera); 1869 } 1870 } 1871 1872 private boolean switchToOtherMode(int mode) { 1873 if (isFinishing() || !isCameraIdle()) return false; 1874 MenuHelper.gotoMode(mode, Camera.this); 1875 mHandler.removeMessages(FIRST_TIME_INIT); 1876 finish(); 1877 return true; 1878 } 1879 1880 public boolean onModeChanged(int mode) { 1881 if (mode != ModePicker.MODE_CAMERA) { 1882 return switchToOtherMode(mode); 1883 } else { 1884 return true; 1885 } 1886 } 1887 1888 public void onSharedPreferenceChanged() { 1889 // ignore the events after "onPause()" 1890 if (mPausing) return; 1891 1892 boolean recordLocation = RecordLocationPreference.get( 1893 mPreferences, getContentResolver()); 1894 mLocationManager.recordLocation(recordLocation); 1895 1896 int cameraId = CameraSettings.readPreferredCameraId(mPreferences); 1897 if (mCameraId != cameraId) { 1898 // Restart the activity to have a crossfade animation. 1899 // TODO: Use SurfaceTexture to implement a better and faster 1900 // animation. 1901 if (mIsImageCaptureIntent) { 1902 // If the intent is camera capture, stay in camera capture mode. 1903 MenuHelper.gotoCameraMode(this, getIntent()); 1904 } else { 1905 MenuHelper.gotoCameraMode(this); 1906 } 1907 1908 finish(); 1909 } else { 1910 setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE); 1911 } 1912 1913 int exposureValue = CameraSettings.readExposure(mPreferences); 1914 updateExposureOnScreenIndicator(exposureValue); 1915 } 1916 1917 @Override 1918 public void onUserInteraction() { 1919 super.onUserInteraction(); 1920 keepScreenOnAwhile(); 1921 } 1922 1923 private void resetScreenOn() { 1924 mHandler.removeMessages(CLEAR_SCREEN_DELAY); 1925 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 1926 } 1927 1928 private void keepScreenOnAwhile() { 1929 mHandler.removeMessages(CLEAR_SCREEN_DELAY); 1930 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 1931 mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY); 1932 } 1933 1934 public void onRestorePreferencesClicked() { 1935 if (mPausing) return; 1936 Runnable runnable = new Runnable() { 1937 public void run() { 1938 restorePreferences(); 1939 } 1940 }; 1941 MenuHelper.confirmAction(this, 1942 getString(R.string.confirm_restore_title), 1943 getString(R.string.confirm_restore_message), 1944 runnable); 1945 } 1946 1947 private void restorePreferences() { 1948 // Reset the zoom. Zoom value is not stored in preference. 1949 if (mParameters.isZoomSupported()) { 1950 mZoomValue = 0; 1951 setCameraParametersWhenIdle(UPDATE_PARAM_ZOOM); 1952 mZoomControl.setZoomIndex(0); 1953 } 1954 if (mIndicatorControlContainer != null) { 1955 mIndicatorControlContainer.dismissSettingPopup(); 1956 CameraSettings.restorePreferences(Camera.this, mPreferences, 1957 mParameters); 1958 mIndicatorControlContainer.reloadPreferences(); 1959 onSharedPreferenceChanged(); 1960 } 1961 } 1962 1963 public void onOverriddenPreferencesClicked() { 1964 if (mPausing) return; 1965 if (mNotSelectableToast == null) { 1966 String str = getResources().getString(R.string.not_selectable_in_scene_mode); 1967 mNotSelectableToast = Toast.makeText(Camera.this, str, Toast.LENGTH_SHORT); 1968 } 1969 mNotSelectableToast.show(); 1970 } 1971 1972 private void showSharePopup() { 1973 Uri uri = mThumbnail.getUri(); 1974 if (mSharePopup == null || !uri.equals(mSharePopup.getUri())) { 1975 mSharePopup = new SharePopup(this, uri, mThumbnail.getBitmap(), 1976 mOrientationCompensation, mPreviewFrameLayout); 1977 } 1978 mSharePopup.showAtLocation(mThumbnailView, Gravity.NO_GRAVITY, 0, 0); 1979 } 1980 1981 @Override 1982 public void onFaceDetection(Face[] faces, android.hardware.Camera camera) { 1983 mFaceView.setFaces(faces); 1984 } 1985 1986 private void showTapToFocusToast() { 1987 // Show the toast. 1988 RotateLayout v = (RotateLayout) findViewById(R.id.tap_to_focus_prompt); 1989 v.setOrientation(mOrientationCompensation); 1990 v.startAnimation(AnimationUtils.loadAnimation(this, R.anim.on_screen_hint_enter)); 1991 v.setVisibility(View.VISIBLE); 1992 mHandler.sendEmptyMessageDelayed(DISMISS_TAP_TO_FOCUS_TOAST, 5000); 1993 // Clear the preference. 1994 Editor editor = mPreferences.edit(); 1995 editor.putBoolean(CameraSettings.KEY_TAP_TO_FOCUS_PROMPT_SHOWN, false); 1996 editor.apply(); 1997 } 1998 1999 private void initializeCapabilities() { 2000 mInitialParams = mCameraDevice.getParameters(); 2001 mFocusManager.initializeParameters(mInitialParams); 2002 mFocusAreaSupported = (mInitialParams.getMaxNumFocusAreas() > 0 2003 && isSupported(Parameters.FOCUS_MODE_AUTO, 2004 mInitialParams.getSupportedFocusModes())); 2005 mMeteringAreaSupported = (mInitialParams.getMaxNumMeteringAreas() > 0); 2006 } 2007} 2008