CaptureModule.java revision dc0369f37b07adb4355113540af3c1f7c82a404e
1/* 2 * Copyright (C) 2014 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 android.app.Activity; 20import android.content.Context; 21import android.content.res.Configuration; 22import android.graphics.Bitmap; 23import android.graphics.Matrix; 24import android.graphics.RectF; 25import android.graphics.SurfaceTexture; 26import android.hardware.Sensor; 27import android.hardware.SensorEvent; 28import android.hardware.SensorEventListener; 29import android.hardware.SensorManager; 30import android.location.Location; 31import android.net.Uri; 32import android.os.Handler; 33import android.provider.MediaStore; 34import android.view.KeyEvent; 35import android.view.OrientationEventListener; 36import android.view.Surface; 37import android.view.TextureView; 38import android.view.View; 39import android.view.View.OnLayoutChangeListener; 40import android.widget.Toast; 41 42import com.android.camera.app.AppController; 43import com.android.camera.app.CameraAppUI; 44import com.android.camera.app.CameraAppUI.BottomBarUISpec; 45import com.android.camera.app.LocationManager; 46import com.android.camera.app.MediaSaver; 47import com.android.camera.debug.DebugPropertyHelper; 48import com.android.camera.debug.Log; 49import com.android.camera.debug.Log.Tag; 50import com.android.camera.hardware.HardwareSpec; 51import com.android.camera.module.ModuleController; 52import com.android.camera.one.OneCamera; 53import com.android.camera.one.OneCamera.AutoFocusState; 54import com.android.camera.one.OneCamera.CaptureReadyCallback; 55import com.android.camera.one.OneCamera.Facing; 56import com.android.camera.one.OneCamera.OpenCallback; 57import com.android.camera.one.OneCamera.PhotoCaptureParameters; 58import com.android.camera.one.OneCamera.PhotoCaptureParameters.Flash; 59import com.android.camera.one.OneCameraManager; 60import com.android.camera.one.Settings3A; 61import com.android.camera.one.v2.OneCameraManagerImpl; 62import com.android.camera.remote.RemoteCameraModule; 63import com.android.camera.session.CaptureSession; 64import com.android.camera.settings.Keys; 65import com.android.camera.settings.SettingsManager; 66import com.android.camera.ui.CountDownView; 67import com.android.camera.ui.PreviewStatusListener; 68import com.android.camera.ui.TouchCoordinate; 69import com.android.camera.util.ApiHelper; 70import com.android.camera.util.CameraUtil; 71import com.android.camera.util.GcamHelper; 72import com.android.camera.util.Size; 73import com.android.camera.util.UsageStatistics; 74import com.android.camera2.R; 75import com.android.ex.camera2.portability.CameraAgent.CameraProxy; 76 77import java.io.File; 78 79/** 80 * New Capture module that is made to support photo and video capture on top of 81 * the OneCamera API, to transparently support GCam. 82 * <p> 83 * This has been a re-write with pieces taken and improved from GCamModule and 84 * PhotoModule, which are to be retired eventually. 85 * <p> 86 * TODO: 87 * <ul> 88 * <li>Server-side logging 89 * <li>Focusing (managed by OneCamera implementations) 90 * <li>Show location dialog on first start 91 * <li>Show resolution dialog on certain devices 92 * <li>Store location 93 * <li>Capture intent 94 * </ul> 95 */ 96public class CaptureModule extends CameraModule 97 implements MediaSaver.QueueListener, 98 ModuleController, 99 CountDownView.OnCountDownStatusListener, 100 OneCamera.PictureCallback, 101 OneCamera.FocusStateListener, 102 OneCamera.ReadyStateChangedListener, 103 PreviewStatusListener.PreviewAreaChangedListener, 104 RemoteCameraModule, 105 SensorEventListener, 106 SettingsManager.OnSettingChangedListener, 107 TextureView.SurfaceTextureListener { 108 109 /** 110 * Called on layout changes. 111 */ 112 private final OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() { 113 @Override 114 public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, 115 int oldTop, int oldRight, int oldBottom) { 116 int width = right - left; 117 int height = bottom - top; 118 updatePreviewTransform(width, height, false); 119 } 120 }; 121 122 /** 123 * Hide AF target UI element. 124 */ 125 Runnable mHideAutoFocusTargetRunnable = new Runnable() { 126 @Override 127 public void run() { 128 // For debug UI off, showAutoFocusSuccess() just hides the AF UI. 129 if (mFocusedAtEnd) { 130 mUI.showAutoFocusSuccess(); 131 } else { 132 mUI.showAutoFocusFailure(); 133 } 134 } 135 }; 136 137 private static final Tag TAG = new Tag("CaptureModule"); 138 private static final String PHOTO_MODULE_STRING_ID = "PhotoModule"; 139 /** Enable additional debug output. */ 140 private static final boolean DEBUG = true; 141 /** 142 * This is the delay before we execute onResume tasks when coming from the 143 * lock screen, to allow time for onPause to execute. 144 * <p> 145 * TODO: Make sure this value is in sync with what we see on L. 146 */ 147 private static final int ON_RESUME_TASKS_DELAY_MSEC = 20; 148 149 /** System Properties switch to enable debugging focus UI. */ 150 private static final boolean CAPTURE_DEBUG_UI = DebugPropertyHelper.showCaptureDebugUI(); 151 152 private final Object mDimensionLock = new Object(); 153 154 /** 155 * Sticky Gcam mode is when this module's sole purpose it to be the Gcam 156 * mode. If true, the device uses {@link PhotoModule} for normal picture 157 * taking. 158 */ 159 private final boolean mStickyGcamCamera; 160 161 /** 162 * Lock for race conditions in the SurfaceTextureListener callbacks. 163 */ 164 private final Object mSurfaceLock = new Object(); 165 /** Controller giving us access to other services. */ 166 private final AppController mAppController; 167 /** The applications settings manager. */ 168 private final SettingsManager mSettingsManager; 169 /** Application context. */ 170 private final Context mContext; 171 private CaptureModuleUI mUI; 172 /** The camera manager used to open cameras. */ 173 private OneCameraManager mCameraManager; 174 /** The currently opened camera device. */ 175 private OneCamera mCamera; 176 /** The direction the currently opened camera is facing to. */ 177 private Facing mCameraFacing = Facing.BACK; 178 /** Whether HDR is currently enabled. */ 179 private boolean mHdrEnabled = false; 180 181 /** The texture used to render the preview in. */ 182 private SurfaceTexture mPreviewTexture; 183 184 /** State by the module state machine. */ 185 private static enum ModuleState { 186 IDLE, 187 WATCH_FOR_NEXT_FRAME_AFTER_PREVIEW_STARTED, 188 UPDATE_TRANSFORM_ON_NEXT_SURFACE_TEXTURE_UPDATE, 189 } 190 191 /** The current state of the module. */ 192 private ModuleState mState = ModuleState.IDLE; 193 /** Current orientation of the device. */ 194 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; 195 /** Current zoom value. */ 196 private float mZoomValue = 1f; 197 /** Current duration of capture timer in seconds. */ 198 private int mTimerDuration; 199 // TODO: Get image capture intent UI working. 200 private boolean mIsImageCaptureIntent; 201 202 /** True if in AF tap-to-focus sequence. */ 203 private boolean mTapToFocusWaitForActiveScan = false; 204 205 /** Persistence of Tap to Focus target UI after scan complete. */ 206 private static final int FOCUS_HOLD_UI_MILLIS = 0; 207 /** Worst case persistence of TTF target UI. */ 208 private static final int FOCUS_UI_TIMEOUT_MILLIS = 2000; 209 /** Results from last tap to focus scan */ 210 private boolean mFocusedAtEnd; 211 /** Sensor manager we use to get the heading of the device. */ 212 private SensorManager mSensorManager; 213 /** Accelerometer. */ 214 private Sensor mAccelerometerSensor; 215 /** Compass. */ 216 private Sensor mMagneticSensor; 217 218 /** Accelerometer data. */ 219 private final float[] mGData = new float[3]; 220 /** Magnetic sensor data. */ 221 private final float[] mMData = new float[3]; 222 /** Temporary rotation matrix. */ 223 private final float[] mR = new float[16]; 224 /** Current compass heading. */ 225 private int mHeading = -1; 226 227 /** Used to fetch and embed the location into captured images. */ 228 private LocationManager mLocationManager; 229 /** Plays sounds for countdown timer. */ 230 private SoundPlayer mCountdownSoundPlayer; 231 232 /** Whether the module is paused right now. */ 233 private boolean mPaused; 234 235 /** Whether this module was resumed from lockscreen capture intent. */ 236 private boolean mIsResumeFromLockScreen = false; 237 238 private final Runnable mResumeTaskRunnable = new Runnable() { 239 @Override 240 public void run() { 241 onResumeTasks(); 242 } 243 }; 244 245 /** Main thread handler. */ 246 private Handler mMainHandler; 247 248 /** Current display rotation in degrees. */ 249 private int mDisplayRotation; 250 /** Current screen width in pixels. */ 251 private int mScreenWidth; 252 /** Current screen height in pixels. */ 253 private int mScreenHeight; 254 /** Current width of preview frames from camera. */ 255 private int mPreviewBufferWidth; 256 /** Current height of preview frames from camera.. */ 257 private int mPreviewBufferHeight; 258 /** Area used by preview. */ 259 RectF mPreviewArea; 260 261 /** The current preview transformation matrix. */ 262 private Matrix mPreviewTranformationMatrix = new Matrix(); 263 /** TODO: This is N5 specific. */ 264 public static final float FULLSCREEN_ASPECT_RATIO = 16 / 9f; 265 266 /** A directory to store debug information in during development. */ 267 private final File mDebugDataDir; 268 269 /** CLEAN UP START */ 270 // private boolean mFirstLayout; 271 // private int[] mTargetFPSRanges; 272 // private float mZoomValue; 273 // private int mSensorOrientation; 274 // private int mLensFacing; 275 // private String mFlashMode; 276 /** CLEAN UP END */ 277 278 public CaptureModule(AppController appController) { 279 this(appController, false); 280 } 281 282 /** Constructs a new capture module. */ 283 public CaptureModule(AppController appController, boolean stickyHdr) { 284 super(appController); 285 mAppController = appController; 286 mContext = mAppController.getAndroidContext(); 287 mSettingsManager = mAppController.getSettingsManager(); 288 mSettingsManager.addListener(this); 289 mDebugDataDir = mContext.getExternalCacheDir(); 290 mStickyGcamCamera = stickyHdr; 291 } 292 293 @Override 294 public void init(CameraActivity activity, boolean isSecureCamera, boolean isCaptureIntent) { 295 Log.d(TAG, "init"); 296 mIsResumeFromLockScreen = isResumeFromLockscreen(activity); 297 mMainHandler = new Handler(activity.getMainLooper()); 298 mCameraManager = mAppController.getCameraManager(); 299 mLocationManager = mAppController.getLocationManager(); 300 mDisplayRotation = CameraUtil.getDisplayRotation(mContext); 301 mCameraFacing = getFacingFromCameraId(mSettingsManager.getInteger( 302 mAppController.getModuleScope(), 303 Keys.KEY_CAMERA_ID)); 304 mUI = new CaptureModuleUI(activity, this, mAppController.getModuleLayoutRoot(), 305 mLayoutListener); 306 mAppController.setPreviewStatusListener(mUI); 307 mPreviewTexture = mAppController.getCameraAppUI().getSurfaceTexture(); 308 mSensorManager = (SensorManager) (mContext.getSystemService(Context.SENSOR_SERVICE)); 309 mAccelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 310 mMagneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); 311 mCountdownSoundPlayer = new SoundPlayer(mContext); 312 313 String action = activity.getIntent().getAction(); 314 mIsImageCaptureIntent = (MediaStore.ACTION_IMAGE_CAPTURE.equals(action) 315 || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action)); 316 View cancelButton = activity.findViewById(R.id.shutter_cancel_button); 317 cancelButton.setOnClickListener(new View.OnClickListener() { 318 @Override 319 public void onClick(View view) { 320 cancelCountDown(); 321 } 322 }); 323 } 324 325 @Override 326 public void onShutterButtonFocus(boolean pressed) { 327 // TODO Auto-generated method stub 328 } 329 330 @Override 331 public void onShutterCoordinate(TouchCoordinate coord) { 332 // TODO Auto-generated method stub 333 } 334 335 @Override 336 public void onShutterButtonClick() { 337 if (mCamera == null) { 338 return; 339 } 340 341 int countDownDuration = mSettingsManager 342 .getInteger(SettingsManager.SCOPE_GLOBAL, Keys.KEY_COUNTDOWN_DURATION); 343 mTimerDuration = countDownDuration; 344 if (countDownDuration > 0) { 345 // Start count down. 346 mAppController.getCameraAppUI().transitionToCancel(); 347 mAppController.getCameraAppUI().hideModeOptions(); 348 mUI.setCountdownFinishedListener(this); 349 mUI.startCountdown(countDownDuration); 350 // Will take picture later via listener callback. 351 } else { 352 takePictureNow(); 353 } 354 } 355 356 private void takePictureNow() { 357 Location location = mLocationManager.getCurrentLocation(); 358 359 // Set up the capture session. 360 long sessionTime = System.currentTimeMillis(); 361 String title = CameraUtil.createJpegName(sessionTime); 362 CaptureSession session = getServices().getCaptureSessionManager() 363 .createNewSession(title, sessionTime, location); 364 365 // Set up the parameters for this capture. 366 PhotoCaptureParameters params = new PhotoCaptureParameters(); 367 params.title = title; 368 params.callback = this; 369 params.orientation = getOrientation(); 370 params.flashMode = getFlashModeFromSettings(); 371 params.heading = mHeading; 372 params.debugDataFolder = mDebugDataDir; 373 params.location = location; 374 375 mCamera.takePicture(params, session); 376 } 377 378 @Override 379 public void onCountDownFinished() { 380 if (mIsImageCaptureIntent) { 381 mAppController.getCameraAppUI().transitionToIntentReviewLayout(); 382 } else { 383 mAppController.getCameraAppUI().transitionToCapture(); 384 } 385 mAppController.getCameraAppUI().showModeOptions(); 386 if (mPaused) { 387 return; 388 } 389 takePictureNow(); 390 } 391 392 @Override 393 public void onRemainingSecondsChanged(int remainingSeconds) { 394 if (remainingSeconds == 1) { 395 mCountdownSoundPlayer.play(R.raw.beep_twice, 0.6f); 396 } else if (remainingSeconds == 2 || remainingSeconds == 3) { 397 mCountdownSoundPlayer.play(R.raw.beep_once, 0.6f); 398 } 399 } 400 401 private void cancelCountDown() { 402 if (mUI.isCountingDown()) { 403 // Cancel on-going countdown. 404 mUI.cancelCountDown(); 405 } 406 mAppController.getCameraAppUI().showModeOptions(); 407 mAppController.getCameraAppUI().transitionToCapture(); 408 } 409 410 @Override 411 public void onQuickExpose() { 412 mMainHandler.post(new Runnable() { 413 @Override 414 public void run() { 415 // Starts the short version of the capture animation UI. 416 mAppController.startPreCaptureAnimation(true); 417 } 418 }); 419 } 420 421 @Override 422 public void onPreviewAreaChanged(RectF previewArea) { 423 mPreviewArea = previewArea; 424 mUI.onPreviewAreaChanged(previewArea); 425 // mUI.updatePreviewAreaRect(previewArea); 426 mUI.positionProgressOverlay(previewArea); 427 } 428 429 @Override 430 public void onSensorChanged(SensorEvent event) { 431 // This is literally the same as the GCamModule implementation. 432 int type = event.sensor.getType(); 433 float[] data; 434 if (type == Sensor.TYPE_ACCELEROMETER) { 435 data = mGData; 436 } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { 437 data = mMData; 438 } else { 439 Log.w(TAG, String.format("Unexpected sensor type %s", event.sensor.getName())); 440 return; 441 } 442 for (int i = 0; i < 3; i++) { 443 data[i] = event.values[i]; 444 } 445 float[] orientation = new float[3]; 446 SensorManager.getRotationMatrix(mR, null, mGData, mMData); 447 SensorManager.getOrientation(mR, orientation); 448 mHeading = (int) (orientation[0] * 180f / Math.PI) % 360; 449 450 if (mHeading < 0) { 451 mHeading += 360; 452 } 453 } 454 455 @Override 456 public void onAccuracyChanged(Sensor sensor, int accuracy) { 457 // TODO Auto-generated method stub 458 } 459 460 @Override 461 public void onQueueStatus(boolean full) { 462 // TODO Auto-generated method stub 463 } 464 465 @Override 466 public void onRemoteShutterPress() { 467 // TODO: Check whether shutter is enabled. 468 onShutterButtonClick(); 469 } 470 471 @Override 472 public void onSurfaceTextureAvailable(final SurfaceTexture surface, int width, int height) { 473 Log.d(TAG, "onSurfaceTextureAvailable"); 474 // Force to re-apply transform matrix here as a workaround for 475 // b/11168275 476 updatePreviewTransform(width, height, true); 477 initSurface(surface); 478 } 479 480 public void initSurface(final SurfaceTexture surface) { 481 mPreviewTexture = surface; 482 closeCamera(); 483 openCameraAndStartPreview(); 484 } 485 486 @Override 487 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 488 Log.d(TAG, "onSurfaceTextureSizeChanged"); 489 resetDefaultBufferSize(); 490 } 491 492 @Override 493 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 494 Log.d(TAG, "onSurfaceTextureDestroyed"); 495 mPreviewTexture = null; 496 closeCamera(); 497 return true; 498 } 499 500 @Override 501 public void onSurfaceTextureUpdated(SurfaceTexture surface) { 502 if (mState == ModuleState.UPDATE_TRANSFORM_ON_NEXT_SURFACE_TEXTURE_UPDATE) { 503 Log.d(TAG, "onSurfaceTextureUpdated --> updatePreviewTransform"); 504 mState = ModuleState.IDLE; 505 CameraAppUI appUI = mAppController.getCameraAppUI(); 506 updatePreviewTransform(appUI.getSurfaceWidth(), appUI.getSurfaceHeight(), true); 507 } 508 } 509 510 @Override 511 public String getModuleStringIdentifier() { 512 return PHOTO_MODULE_STRING_ID; 513 } 514 515 @Override 516 public void resume() { 517 // Add delay on resume from lock screen only, in order to to speed up 518 // the onResume --> onPause --> onResume cycle from lock screen. 519 // Don't do always because letting go of thread can cause delay. 520 if (mIsResumeFromLockScreen) { 521 Log.v(TAG, "Delayng onResumeTasks from lock screen. " + System.currentTimeMillis()); 522 // Note: onPauseAfterSuper() will delete this runnable, so we will 523 // at most have 1 copy queued up. 524 mMainHandler.postDelayed(mResumeTaskRunnable, ON_RESUME_TASKS_DELAY_MSEC); 525 } else { 526 onResumeTasks(); 527 } 528 } 529 530 private void onResumeTasks() { 531 Log.d(TAG, "onResumeTasks + " + System.currentTimeMillis()); 532 mPaused = false; 533 mAppController.getCameraAppUI().onChangeCamera(); 534 mAppController.addPreviewAreaSizeChangedListener(this); 535 resetDefaultBufferSize(); 536 getServices().getRemoteShutterListener().onModuleReady(this); 537 // TODO: Check if we can really take a photo right now (memory, camera 538 // state, ... ). 539 mAppController.getCameraAppUI().enableModeOptions(); 540 mAppController.setShutterEnabled(true); 541 542 // TODO: Remove once Gcam is properly tuned on Shamu and ready for 543 // quality feedback. 544 if (mStickyGcamCamera && ApiHelper.IS_NEXUS_6) { 545 Toast.makeText(mContext, 546 "Shamu HDR+ still in tuning, don't file image quality issues yet", 547 Toast.LENGTH_SHORT).show(); 548 } 549 // Get events from the accelerometer and magnetic sensor. 550 if (mAccelerometerSensor != null) { 551 mSensorManager.registerListener(this, mAccelerometerSensor, 552 SensorManager.SENSOR_DELAY_NORMAL); 553 } 554 if (mMagneticSensor != null) { 555 mSensorManager.registerListener(this, mMagneticSensor, 556 SensorManager.SENSOR_DELAY_NORMAL); 557 } 558 mHdrEnabled = mStickyGcamCamera || mAppController.getSettingsManager().getInteger( 559 SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_HDR_PLUS) == 1; 560 561 // This means we are resuming with an existing preview texture. This 562 // means we will never get the onSurfaceTextureAvailable call. So we 563 // have to open the camera and start the preview here. 564 if (mPreviewTexture != null) { 565 initSurface(mPreviewTexture); 566 } 567 568 mCountdownSoundPlayer.loadSound(R.raw.beep_once); 569 mCountdownSoundPlayer.loadSound(R.raw.beep_twice); 570 } 571 572 @Override 573 public void pause() { 574 mPaused = true; 575 cancelCountDown(); 576 resetTextureBufferSize(); 577 closeCamera(); 578 mCountdownSoundPlayer.unloadSound(R.raw.beep_once); 579 mCountdownSoundPlayer.unloadSound(R.raw.beep_twice); 580 // Remove delayed resume trigger, if it hasn't been executed yet. 581 mMainHandler.removeCallbacksAndMessages(null); 582 583 // Unregister the sensors. 584 if (mAccelerometerSensor != null) { 585 mSensorManager.unregisterListener(this, mAccelerometerSensor); 586 } 587 if (mMagneticSensor != null) { 588 mSensorManager.unregisterListener(this, mMagneticSensor); 589 } 590 } 591 592 @Override 593 public void destroy() { 594 mCountdownSoundPlayer.release(); 595 } 596 597 @Override 598 public void onLayoutOrientationChanged(boolean isLandscape) { 599 Log.d(TAG, "onLayoutOrientationChanged"); 600 } 601 602 @Override 603 public void onOrientationChanged(int orientation) { 604 // We keep the last known orientation. So if the user first orient 605 // the camera then point the camera to floor or sky, we still have 606 // the correct orientation. 607 if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) { 608 return; 609 } 610 mOrientation = CameraUtil.roundOrientation(orientation, mOrientation); 611 } 612 613 @Override 614 public void onCameraAvailable(CameraProxy cameraProxy) { 615 // Ignore since we manage the camera ourselves until we remove this. 616 } 617 618 @Override 619 public void hardResetSettings(SettingsManager settingsManager) { 620 if (mStickyGcamCamera) { 621 // Sitcky HDR+ mode should hard reset HDR+ to on, and camera back 622 // facing. 623 settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_HDR_PLUS, true); 624 settingsManager.set(mAppController.getModuleScope(), Keys.KEY_CAMERA_ID, 625 getBackFacingCameraId()); 626 } 627 } 628 629 @Override 630 public HardwareSpec getHardwareSpec() { 631 return new HardwareSpec() { 632 @Override 633 public boolean isFrontCameraSupported() { 634 return true; 635 } 636 637 @Override 638 public boolean isHdrSupported() { 639 // TODO: Check if the device has HDR and not HDR+. 640 return false; 641 } 642 643 @Override 644 public boolean isHdrPlusSupported() { 645 return GcamHelper.hasGcamCapture(); 646 } 647 648 @Override 649 public boolean isFlashSupported() { 650 return true; 651 } 652 }; 653 } 654 655 @Override 656 public BottomBarUISpec getBottomBarSpec() { 657 CameraAppUI.BottomBarUISpec bottomBarSpec = new CameraAppUI.BottomBarUISpec(); 658 bottomBarSpec.enableGridLines = true; 659 bottomBarSpec.enableCamera = true; 660 bottomBarSpec.cameraCallback = getCameraCallback(); 661 bottomBarSpec.enableHdr = GcamHelper.hasGcamCapture(); 662 bottomBarSpec.hdrCallback = getHdrButtonCallback(); 663 bottomBarSpec.enableSelfTimer = true; 664 bottomBarSpec.showSelfTimer = true; 665 if (!mHdrEnabled) { 666 bottomBarSpec.enableFlash = true; 667 } 668 return bottomBarSpec; 669 } 670 671 @Override 672 public boolean isUsingBottomBar() { 673 return true; 674 } 675 676 @Override 677 public boolean onKeyDown(int keyCode, KeyEvent event) { 678 switch (keyCode) { 679 case KeyEvent.KEYCODE_CAMERA: 680 case KeyEvent.KEYCODE_DPAD_CENTER: 681 if (mUI.isCountingDown()) { 682 cancelCountDown(); 683 } else if (event.getRepeatCount() == 0) { 684 onShutterButtonClick(); 685 } 686 return true; 687 case KeyEvent.KEYCODE_VOLUME_UP: 688 case KeyEvent.KEYCODE_VOLUME_DOWN: 689 // Prevent default. 690 return true; 691 } 692 return false; 693 } 694 695 @Override 696 public boolean onKeyUp(int keyCode, KeyEvent event) { 697 switch (keyCode) { 698 case KeyEvent.KEYCODE_VOLUME_UP: 699 case KeyEvent.KEYCODE_VOLUME_DOWN: 700 onShutterButtonClick(); 701 return true; 702 } 703 return false; 704 } 705 706 /** 707 * Focus sequence starts for zone around tap location for single tap. 708 */ 709 @Override 710 public void onSingleTapUp(View view, int x, int y) { 711 Log.v(TAG, "onSingleTapUp x=" + x + " y=" + y); 712 // TODO: This should query actual capability. 713 if (mCameraFacing == Facing.FRONT) { 714 return; 715 } 716 triggerFocusAtScreenCoord(x, y); 717 } 718 719 // TODO: Consider refactoring FocusOverlayManager. 720 // Currently AF state transitions are controlled in OneCameraImpl. 721 // PhotoModule uses FocusOverlayManager which uses API1/portability 722 // logic and coordinates. 723 private void triggerFocusAtScreenCoord(int x, int y) { 724 mTapToFocusWaitForActiveScan = true; 725 // Show UI immediately even though scan has not started yet. 726 float minEdge = Math.min(mPreviewArea.width(), mPreviewArea.height()); 727 mUI.setAutoFocusTarget(x, y, false, 728 (int) (Settings3A.getAutoFocusRegionWidth() * mZoomValue * minEdge), 729 (int) (Settings3A.getMeteringRegionWidth() * mZoomValue * minEdge)); 730 mUI.showAutoFocusInProgress(); 731 732 // Cancel any scheduled auto focus target UI actions. 733 mMainHandler.removeCallbacks(mHideAutoFocusTargetRunnable); 734 // Timeout in case camera fails to stop (unlikely). 735 mMainHandler.postDelayed(new Runnable() { 736 @Override 737 public void run() { 738 mMainHandler.post(mHideAutoFocusTargetRunnable); 739 } 740 }, FOCUS_UI_TIMEOUT_MILLIS); 741 742 // Normalize coordinates to [0,1] per CameraOne API. 743 float points[] = new float[2]; 744 points[0] = (x - mPreviewArea.left) / mPreviewArea.width(); 745 points[1] = (y - mPreviewArea.top) / mPreviewArea.height(); 746 747 // Rotate coordinates to portrait orientation per CameraOne API. 748 Matrix rotationMatrix = new Matrix(); 749 rotationMatrix.setRotate(mDisplayRotation, 0.5f, 0.5f); 750 rotationMatrix.mapPoints(points); 751 mCamera.triggerFocusAndMeterAtPoint(points[0], points[1]); 752 753 // Log touch (screen coordinates). 754 if (mZoomValue == 1f) { 755 TouchCoordinate touchCoordinate = new TouchCoordinate(x - mPreviewArea.left, 756 y - mPreviewArea.top, mPreviewArea.width(), mPreviewArea.height()); 757 // TODO: Add to logging: duration, rotation. 758 UsageStatistics.instance().tapToFocus(touchCoordinate, null); 759 } 760 } 761 762 /** 763 * Show AF target in center of preview. 764 */ 765 private void setAutoFocusTargetPassive() { 766 float minEdge = Math.min(mPreviewArea.width(), mPreviewArea.height()); 767 mUI.setAutoFocusTarget((int) mPreviewArea.centerX(), (int) mPreviewArea.centerY(), 768 true, 769 (int) (Settings3A.getAutoFocusRegionWidth() * mZoomValue * minEdge), 770 (int) (Settings3A.getMeteringRegionWidth() * mZoomValue * minEdge)); 771 } 772 773 /** 774 * Update UI based on AF state changes. 775 */ 776 @Override 777 public void onFocusStatusUpdate(final AutoFocusState state) { 778 Log.v(TAG, "AF status is state:" + state); 779 780 switch (state) { 781 case PASSIVE_SCAN: 782 mMainHandler.removeCallbacks(mHideAutoFocusTargetRunnable); 783 mMainHandler.post(new Runnable() { 784 @Override 785 public void run() { 786 setAutoFocusTargetPassive(); 787 mUI.showAutoFocusInProgress(); 788 } 789 }); 790 break; 791 case ACTIVE_SCAN: 792 mTapToFocusWaitForActiveScan = false; 793 break; 794 case PASSIVE_FOCUSED: 795 case PASSIVE_UNFOCUSED: 796 mMainHandler.post(new Runnable() { 797 @Override 798 public void run() { 799 setAutoFocusTargetPassive(); 800 mMainHandler.post(mHideAutoFocusTargetRunnable); 801 } 802 }); 803 break; 804 case ACTIVE_FOCUSED: 805 case ACTIVE_UNFOCUSED: 806 if (!mTapToFocusWaitForActiveScan) { 807 mFocusedAtEnd = state != AutoFocusState.ACTIVE_UNFOCUSED; 808 mMainHandler.removeCallbacks(mHideAutoFocusTargetRunnable); 809 mMainHandler.post(mHideAutoFocusTargetRunnable); 810 } 811 break; 812 } 813 } 814 815 @Override 816 public void onReadyStateChanged(boolean readyForCapture) { 817 if (readyForCapture) { 818 mAppController.getCameraAppUI().enableModeOptions(); 819 } 820 mAppController.setShutterEnabled(readyForCapture); 821 } 822 823 @Override 824 public String getPeekAccessibilityString() { 825 return mAppController.getAndroidContext() 826 .getResources().getString(R.string.photo_accessibility_peek); 827 } 828 829 @Override 830 public void onThumbnailResult(Bitmap bitmap) { 831 // TODO 832 } 833 834 @Override 835 public void onPictureTaken(CaptureSession session) { 836 mAppController.getCameraAppUI().enableModeOptions(); 837 mAppController.getCameraAppUI().setShutterButtonEnabled(true); 838 } 839 840 @Override 841 public void onPictureSaved(Uri uri) { 842 mAppController.notifyNewMedia(uri); 843 } 844 845 @Override 846 public void onTakePictureProgress(float progress) { 847 mUI.setPictureTakingProgress((int) (progress * 100)); 848 } 849 850 @Override 851 public void onPictureTakenFailed() { 852 } 853 854 @Override 855 public void onSettingChanged(SettingsManager settingsManager, String key) { 856 // TODO Auto-generated method stub 857 } 858 859 /** 860 * Updates the preview transform matrix to adapt to the current preview 861 * width, height, and orientation. 862 */ 863 public void updatePreviewTransform() { 864 int width; 865 int height; 866 synchronized (mDimensionLock) { 867 width = mScreenWidth; 868 height = mScreenHeight; 869 } 870 updatePreviewTransform(width, height); 871 } 872 873 /** 874 * Set zoom value. 875 * 876 * @param zoom Zoom value, must be between 1.0 and mCamera.getMaxZoom(). 877 */ 878 public void setZoom(float zoom) { 879 mZoomValue = zoom; 880 if (mCamera != null) { 881 mCamera.setZoom(zoom); 882 } 883 } 884 885 /** 886 * TODO: Remove this method once we are in pure CaptureModule land. 887 */ 888 private String getBackFacingCameraId() { 889 if (!(mCameraManager instanceof OneCameraManagerImpl)) { 890 throw new IllegalStateException("This should never be called with Camera API V1"); 891 } 892 OneCameraManagerImpl manager = (OneCameraManagerImpl) mCameraManager; 893 return manager.getFirstBackCameraId(); 894 } 895 896 /** 897 * @return Depending on whether we're in sticky-HDR mode or not, return the 898 * proper callback to be used for when the HDR/HDR+ button is 899 * pressed. 900 */ 901 private ButtonManager.ButtonCallback getHdrButtonCallback() { 902 if (mStickyGcamCamera) { 903 return new ButtonManager.ButtonCallback() { 904 @Override 905 public void onStateChanged(int state) { 906 if (mPaused) { 907 return; 908 } 909 if (state == ButtonManager.ON) { 910 throw new IllegalStateException( 911 "Can't leave hdr plus mode if switching to hdr plus mode."); 912 } 913 SettingsManager settingsManager = mAppController.getSettingsManager(); 914 settingsManager.set(mAppController.getModuleScope(), 915 Keys.KEY_REQUEST_RETURN_HDR_PLUS, false); 916 switchToRegularCapture(); 917 } 918 }; 919 } else { 920 return new ButtonManager.ButtonCallback() { 921 @Override 922 public void onStateChanged(int hdrEnabled) { 923 if (mPaused) { 924 return; 925 } 926 Log.d(TAG, "HDR enabled =" + hdrEnabled); 927 mHdrEnabled = hdrEnabled == 1; 928 switchCamera(); 929 } 930 }; 931 } 932 } 933 934 /** 935 * @return Depending on whether we're in sticky-HDR mode or not, this 936 * returns the proper callback to be used for when the camera 937 * (front/back switch) button is pressed. 938 */ 939 private ButtonManager.ButtonCallback getCameraCallback() { 940 if (mStickyGcamCamera) { 941 return new ButtonManager.ButtonCallback() { 942 @Override 943 public void onStateChanged(int state) { 944 if (mPaused) { 945 return; 946 } 947 948 // At the time this callback is fired, the camera id setting 949 // has changed to the desired camera. 950 SettingsManager settingsManager = mAppController.getSettingsManager(); 951 if (Keys.isCameraBackFacing(settingsManager, 952 mAppController.getModuleScope())) { 953 throw new IllegalStateException( 954 "Hdr plus should never be switching from front facing camera."); 955 } 956 957 // Switch to photo mode, but request a return to hdr plus on 958 // switching to back camera again. 959 settingsManager.set(mAppController.getModuleScope(), 960 Keys.KEY_REQUEST_RETURN_HDR_PLUS, true); 961 switchToRegularCapture(); 962 } 963 }; 964 } else { 965 return new ButtonManager.ButtonCallback() { 966 @Override 967 public void onStateChanged(int cameraId) { 968 if (mPaused) { 969 return; 970 } 971 972 // At the time this callback is fired, the camera id 973 // has be set to the desired camera. 974 mSettingsManager.set(mAppController.getModuleScope(), Keys.KEY_CAMERA_ID, 975 cameraId); 976 977 Log.d(TAG, "Start to switch camera. cameraId=" + cameraId); 978 mCameraFacing = getFacingFromCameraId(cameraId); 979 switchCamera(); 980 } 981 }; 982 } 983 } 984 985 /** 986 * Switches to PhotoModule to do regular photo captures. 987 * <p> 988 * TODO: Remove this once we use CaptureModule for photo taking. 989 */ 990 private void switchToRegularCapture() { 991 // Turn off HDR+ before switching back to normal photo mode. 992 SettingsManager settingsManager = mAppController.getSettingsManager(); 993 settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_HDR_PLUS, false); 994 995 // Disable this button to prevent callbacks from this module from firing 996 // while we are transitioning modules. 997 ButtonManager buttonManager = mAppController.getButtonManager(); 998 buttonManager.disableButtonClick(ButtonManager.BUTTON_HDR_PLUS); 999 mAppController.getCameraAppUI().freezeScreenUntilPreviewReady(); 1000 mAppController.onModeSelected(mContext.getResources().getInteger( 1001 R.integer.camera_mode_photo)); 1002 buttonManager.enableButtonClick(ButtonManager.BUTTON_HDR_PLUS); 1003 } 1004 1005 /** 1006 * Called when the preview started. Informs the app controller and queues a 1007 * transform update when the next preview frame arrives. 1008 */ 1009 private void onPreviewStarted() { 1010 if (mState == ModuleState.WATCH_FOR_NEXT_FRAME_AFTER_PREVIEW_STARTED) { 1011 mState = ModuleState.UPDATE_TRANSFORM_ON_NEXT_SURFACE_TEXTURE_UPDATE; 1012 } 1013 mAppController.onPreviewStarted(); 1014 } 1015 1016 /** 1017 * Update the preview transform based on the new dimensions. Will not force 1018 * an update, if it's not necessary. 1019 */ 1020 private void updatePreviewTransform(int incomingWidth, int incomingHeight) { 1021 updatePreviewTransform(incomingWidth, incomingHeight, false); 1022 } 1023 1024 /*** 1025 * Update the preview transform based on the new dimensions. TODO: Make work 1026 * with all: aspect ratios/resolutions x screens/cameras. 1027 */ 1028 private void updatePreviewTransform(int incomingWidth, int incomingHeight, 1029 boolean forceUpdate) { 1030 Log.d(TAG, "updatePreviewTransform: " + incomingWidth + " x " + incomingHeight); 1031 1032 synchronized (mDimensionLock) { 1033 int incomingRotation = CameraUtil 1034 .getDisplayRotation(mContext); 1035 // Check for an actual change: 1036 if (mScreenHeight == incomingHeight && mScreenWidth == incomingWidth && 1037 incomingRotation == mDisplayRotation && !forceUpdate) { 1038 return; 1039 } 1040 // Update display rotation and dimensions 1041 mDisplayRotation = incomingRotation; 1042 mScreenWidth = incomingWidth; 1043 mScreenHeight = incomingHeight; 1044 updatePreviewBufferDimension(); 1045 1046 mPreviewTranformationMatrix = mAppController.getCameraAppUI().getPreviewTransform( 1047 mPreviewTranformationMatrix); 1048 int width = mScreenWidth; 1049 int height = mScreenHeight; 1050 1051 // Assumptions: 1052 // - Aspect ratio for the sensor buffers is in landscape 1053 // orientation, 1054 // - Dimensions of buffers received are rotated to the natural 1055 // device orientation. 1056 // - The contents of each buffer are rotated by the inverse of 1057 // the display rotation. 1058 // - Surface scales the buffer to fit the current view bounds. 1059 1060 // Get natural orientation and buffer dimensions 1061 int naturalOrientation = CaptureModuleUtil 1062 .getDeviceNaturalOrientation(mContext); 1063 int effectiveWidth = mPreviewBufferWidth; 1064 int effectiveHeight = mPreviewBufferHeight; 1065 1066 if (DEBUG) { 1067 Log.v(TAG, "Rotation: " + mDisplayRotation); 1068 Log.v(TAG, "Screen Width: " + mScreenWidth); 1069 Log.v(TAG, "Screen Height: " + mScreenHeight); 1070 Log.v(TAG, "Buffer width: " + mPreviewBufferWidth); 1071 Log.v(TAG, "Buffer height: " + mPreviewBufferHeight); 1072 Log.v(TAG, "Natural orientation: " + naturalOrientation); 1073 } 1074 1075 // If natural orientation is portrait, rotate the buffer 1076 // dimensions 1077 if (naturalOrientation == Configuration.ORIENTATION_PORTRAIT) { 1078 int temp = effectiveWidth; 1079 effectiveWidth = effectiveHeight; 1080 effectiveHeight = temp; 1081 } 1082 1083 // Find and center view rect and buffer rect 1084 RectF viewRect = new RectF(0, 0, width, height); 1085 RectF bufRect = new RectF(0, 0, effectiveWidth, effectiveHeight); 1086 float centerX = viewRect.centerX(); 1087 float centerY = viewRect.centerY(); 1088 bufRect.offset(centerX - bufRect.centerX(), centerY - bufRect.centerY()); 1089 1090 // Undo ScaleToFit.FILL done by the surface 1091 mPreviewTranformationMatrix.setRectToRect(viewRect, bufRect, Matrix.ScaleToFit.FILL); 1092 1093 // Rotate buffer contents to proper orientation 1094 mPreviewTranformationMatrix.postRotate(getPreviewOrientation(mDisplayRotation), 1095 centerX, centerY); 1096 1097 // TODO: This is probably only working for the N5. Need to test 1098 // on a device like N10 with different sensor orientation. 1099 if ((mDisplayRotation % 180) == 90) { 1100 int temp = effectiveWidth; 1101 effectiveWidth = effectiveHeight; 1102 effectiveHeight = temp; 1103 } 1104 1105 // Scale to fit view, cropping the longest dimension 1106 float scale = 1107 Math.min(width / (float) effectiveWidth, height 1108 / (float) effectiveHeight); 1109 mPreviewTranformationMatrix.postScale(scale, scale, centerX, centerY); 1110 1111 // TODO: Take these quantities from mPreviewArea. 1112 float previewWidth = effectiveWidth * scale; 1113 float previewHeight = effectiveHeight * scale; 1114 float previewCenterX = previewWidth / 2; 1115 float previewCenterY = previewHeight / 2; 1116 mPreviewTranformationMatrix.postTranslate(previewCenterX - centerX, previewCenterY 1117 - centerY); 1118 1119 mAppController.updatePreviewTransform(mPreviewTranformationMatrix); 1120 mAppController.getCameraAppUI().hideLetterboxing(); 1121 // if (mGcamProxy != null) { 1122 // mGcamProxy.postSetAspectRatio(mFinalAspectRatio); 1123 // } 1124 // mUI.updatePreviewAreaRect(new RectF(0, 0, previewWidth, 1125 // previewHeight)); 1126 1127 // TODO: Add face detection. 1128 // Characteristics info = 1129 // mapp.getCameraProvider().getCharacteristics(0); 1130 // mUI.setupFaceDetection(CameraUtil.getDisplayOrientation(incomingRotation, 1131 // info), false); 1132 // updateCamera2FaceBoundTransform(new 1133 // RectF(mEffectiveCropRegion), 1134 // new RectF(0, 0, mBufferWidth, mBufferHeight), 1135 // new RectF(0, 0, previewWidth, previewHeight), getRotation()); 1136 } 1137 } 1138 1139 /** 1140 * Based on the current picture size, selects the best preview dimension and 1141 * stores it in {@link #mPreviewBufferWidth} and 1142 * {@link #mPreviewBufferHeight}. 1143 */ 1144 private void updatePreviewBufferDimension() { 1145 if (mCamera == null) { 1146 return; 1147 } 1148 1149 Size pictureSize = getPictureSizeFromSettings(); 1150 Size previewBufferSize = mCamera.pickPreviewSize(pictureSize, mContext); 1151 mPreviewBufferWidth = previewBufferSize.getWidth(); 1152 mPreviewBufferHeight = previewBufferSize.getHeight(); 1153 } 1154 1155 /** 1156 * Resets the default buffer size to the initially calculated size. 1157 */ 1158 private void resetDefaultBufferSize() { 1159 synchronized (mSurfaceLock) { 1160 if (mPreviewTexture != null) { 1161 mPreviewTexture.setDefaultBufferSize(mPreviewBufferWidth, mPreviewBufferHeight); 1162 } 1163 } 1164 } 1165 1166 /** 1167 * Open camera and start the preview. 1168 */ 1169 private void openCameraAndStartPreview() { 1170 // Only enable HDR on the back camera 1171 boolean useHdr = mHdrEnabled && mCameraFacing == Facing.BACK; 1172 mCameraManager.open(mCameraFacing, useHdr, getPictureSizeFromSettings(), 1173 new OpenCallback() { 1174 @Override 1175 public void onFailure() { 1176 Log.e(TAG, "Could not open camera."); 1177 mCamera = null; 1178 mAppController.showErrorAndFinish(R.string.cannot_connect_camera); 1179 } 1180 1181 @Override 1182 public void onCameraOpened(final OneCamera camera) { 1183 Log.d(TAG, "onCameraOpened: " + camera); 1184 mCamera = camera; 1185 updatePreviewBufferDimension(); 1186 1187 // If the surface texture is not destroyed, it may have 1188 // the last frame lingering. We need to hold off setting 1189 // transform until preview is started. 1190 resetDefaultBufferSize(); 1191 mState = ModuleState.WATCH_FOR_NEXT_FRAME_AFTER_PREVIEW_STARTED; 1192 Log.d(TAG, "starting preview ..."); 1193 1194 // TODO: Consider rolling these two calls into one. 1195 camera.startPreview(new Surface(mPreviewTexture), 1196 new CaptureReadyCallback() { 1197 @Override 1198 public void onSetupFailed() { 1199 Log.e(TAG, "Could not set up preview."); 1200 mCamera.close(null); 1201 mCamera = null; 1202 // TODO: Show an error message and exit. 1203 } 1204 1205 @Override 1206 public void onReadyForCapture() { 1207 Log.d(TAG, "Ready for capture."); 1208 onPreviewStarted(); 1209 // Enable zooming after preview has 1210 // started. 1211 mUI.initializeZoom(mCamera.getMaxZoom()); 1212 mCamera.setFocusStateListener(CaptureModule.this); 1213 mCamera.setReadyStateChangedListener(CaptureModule.this); 1214 } 1215 }); 1216 } 1217 }); 1218 } 1219 1220 private void closeCamera() { 1221 if (mCamera != null) { 1222 mCamera.setFocusStateListener(null); 1223 mCamera.close(null); 1224 mCamera = null; 1225 } 1226 } 1227 1228 private int getOrientation() { 1229 if (mAppController.isAutoRotateScreen()) { 1230 return mDisplayRotation; 1231 } else { 1232 return mOrientation; 1233 } 1234 } 1235 1236 /** 1237 * @return Whether we are resuming from within the lockscreen. 1238 */ 1239 private static boolean isResumeFromLockscreen(Activity activity) { 1240 String action = activity.getIntent().getAction(); 1241 return (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action) 1242 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)); 1243 } 1244 1245 /** 1246 * Re-initialize the camera if e.g. the HDR mode or facing property changed. 1247 */ 1248 private void switchCamera() { 1249 if (mPaused) { 1250 return; 1251 } 1252 cancelCountDown(); 1253 mAppController.freezeScreenUntilPreviewReady(); 1254 initSurface(mPreviewTexture); 1255 1256 // TODO: Un-comment once we have focus back. 1257 // if (mFocusManager != null) { 1258 // mFocusManager.removeMessages(); 1259 // } 1260 // mFocusManager.setMirror(mMirror); 1261 } 1262 1263 private Size getPictureSizeFromSettings() { 1264 String pictureSizeKey = mCameraFacing == Facing.FRONT ? Keys.KEY_PICTURE_SIZE_FRONT 1265 : Keys.KEY_PICTURE_SIZE_BACK; 1266 return mSettingsManager.getSize(SettingsManager.SCOPE_GLOBAL, pictureSizeKey); 1267 } 1268 1269 private int getPreviewOrientation(int deviceOrientationDegrees) { 1270 // Important: Camera2 buffers are already rotated to the natural 1271 // orientation of the device (at least for the back-camera). 1272 1273 // TODO: Remove this hack for the front camera as soon as b/16637957 is 1274 // fixed. 1275 if (mCameraFacing == Facing.FRONT) { 1276 deviceOrientationDegrees += 180; 1277 } 1278 return (360 - deviceOrientationDegrees) % 360; 1279 } 1280 1281 /** 1282 * Returns which way around the camera is facing, based on it's ID. 1283 * <p> 1284 * TODO: This needs to change so that we store the direction directly in the 1285 * settings, rather than a Camera ID. 1286 */ 1287 private static Facing getFacingFromCameraId(int cameraId) { 1288 return cameraId == 1 ? Facing.FRONT : Facing.BACK; 1289 } 1290 1291 private void resetTextureBufferSize() { 1292 // Reset the default buffer sizes on the shared SurfaceTexture 1293 // so they are not scaled for gcam. 1294 // 1295 // According to the documentation for 1296 // SurfaceTexture.setDefaultBufferSize, 1297 // photo and video based image producers (presumably only Camera 1 api), 1298 // override this buffer size. Any module that uses egl to render to a 1299 // SurfaceTexture must have these buffer sizes reset manually. Otherwise 1300 // the SurfaceTexture cannot be transformed by matrix set on the 1301 // TextureView. 1302 if (mPreviewTexture != null) { 1303 mPreviewTexture.setDefaultBufferSize(mAppController.getCameraAppUI().getSurfaceWidth(), 1304 mAppController.getCameraAppUI().getSurfaceHeight()); 1305 } 1306 } 1307 1308 /** 1309 * @return The currently set Flash settings. Defaults to AUTO if the setting 1310 * could not be parsed. 1311 */ 1312 private Flash getFlashModeFromSettings() { 1313 String flashSetting = mSettingsManager.getString(mAppController.getCameraScope(), 1314 Keys.KEY_FLASH_MODE); 1315 try { 1316 return Flash.valueOf(flashSetting.toUpperCase()); 1317 } catch (IllegalArgumentException ex) { 1318 Log.w(TAG, "Could not parse Flash Setting. Defaulting to AUTO."); 1319 return Flash.AUTO; 1320 } 1321 } 1322} 1323