import com.android.camera.debug.DebugPropertyHelper;
import com.android.camera.debug.Log;
import com.android.camera.debug.Log.Tag;
+import com.android.camera.device.CameraId;
import com.android.camera.hardware.HardwareSpec;
import com.android.camera.hardware.HeadingSensor;
import com.android.camera.module.ModuleController;
import com.android.camera.one.OneCamera.OpenCallback;
import com.android.camera.one.OneCamera.PhotoCaptureParameters;
import com.android.camera.one.OneCameraAccessException;
+import com.android.camera.one.OneCameraCaptureSetting;
import com.android.camera.one.OneCameraCharacteristics;
+import com.android.camera.one.OneCameraException;
import com.android.camera.one.OneCameraManager;
-import com.android.camera.one.v2.OneCameraManagerImpl;
+import com.android.camera.one.OneCameraModule;
+import com.android.camera.one.OneCameraOpener;
+import com.android.camera.one.config.OneCameraFeatureConfig;
import com.android.camera.one.v2.photo.ImageRotationCalculator;
import com.android.camera.one.v2.photo.ImageRotationCalculatorImpl;
import com.android.camera.remote.RemoteCameraModule;
import com.android.camera.session.CaptureSession;
import com.android.camera.settings.Keys;
import com.android.camera.settings.SettingsManager;
+import com.android.camera.stats.CaptureStats;
import com.android.camera.stats.UsageStatistics;
import com.android.camera.stats.profiler.Profile;
import com.android.camera.stats.profiler.Profiler;
import com.android.camera.ui.focus.FocusController;
import com.android.camera.ui.focus.FocusSound;
import com.android.camera.util.AndroidServices;
+import com.android.camera.util.ApiHelper;
import com.android.camera.util.CameraUtil;
import com.android.camera.util.GcamHelper;
import com.android.camera.util.Size;
import com.android.camera2.R;
import com.android.ex.camera2.portability.CameraAgent.CameraProxy;
+import com.google.common.logging.eventprotos;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
+import javax.annotation.Nonnull;
+
/**
* New Capture module that is made to support photo and video capture on top of
* the OneCamera API, to transparently support GCam.
RemoteCameraModule {
private static final Tag TAG = new Tag("CaptureModule");
- private static final String PHOTO_MODULE_STRING_ID = "PhotoModule";
/** Enable additional debug output. */
private static final boolean DEBUG = true;
+ /** Workaround Flag for b/19271661 to use autotransformation in Capture Layout in Nexus4 **/
+ private static final boolean USE_AUTOTRANSFORM_UI_LAYOUT = ApiHelper.IS_NEXUS_4;
/** Timeout for camera open/close operations. */
private static final int CAMERA_OPEN_CLOSE_TIMEOUT_MILLIS = 2500;
/** Module UI. */
private CaptureModuleUI mUI;
/** The camera manager used to open cameras. */
- private OneCameraManager mCameraManager;
+ private OneCameraOpener mOneCameraOpener;
+ /** The manager to query for camera device information */
+ private OneCameraManager mOneCameraManager;
/** The currently opened camera device, or null if the camera is closed. */
private OneCamera mCamera;
/** The selected picture size. */
private boolean mHdrSceneEnabled = false;
private boolean mHdrPlusEnabled = false;
private final Object mSurfaceTextureLock = new Object();
+ /**
+ * Flag that is used when Fatal Error Handler is running and the app should
+ * not continue execution
+ */
+ private boolean mShowErrorAndFinish;
+ private TouchCoordinate mLastShutterTouchCoordinate = null;
private FocusController mFocusController;
private OneCameraCharacteristics mCameraCharacteristics;
@Override
public boolean shouldAutoAdjustTransformMatrixOnLayout() {
- return false;
+ return USE_AUTOTRANSFORM_UI_LAYOUT;
}
@Override
public boolean onSingleTapUp(MotionEvent ev) {
Point tapPoint = new Point((int) ev.getX(), (int) ev.getY());
Log.v(TAG, "onSingleTapUpPreview location=" + tapPoint);
- // TODO: This should query actual capability.
- if (mCameraFacing == Facing.FRONT) {
+ if (!mCameraCharacteristics.isAutoExposureSupported() &&
+ !mCameraCharacteristics.isAutoFocusSupported()) {
return false;
}
startActiveFocusAt(tapPoint.x, tapPoint.y);
public void onBurstReadyStateChanged(boolean ready) {
// TODO: This needs to take into account the state of
// the whole system, not just burst.
- mAppController.setShutterEnabled(ready);
+ onReadyStateChanged(false);
}
});
mMediaActionSound = new MediaActionSound();
guard.stop();
}
- private void updateCameraCharacteristics() {
+ private boolean updateCameraCharacteristics() {
try {
- mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraFacing);
- } catch (OneCameraAccessException ocae) {
- mAppController.showErrorAndFinish(R.string.cannot_connect_camera);
- return;
- }
+ CameraId cameraId = mOneCameraManager.findFirstCameraFacing(mCameraFacing);
+ if (cameraId != null && cameraId.getValue() != null) {
+ mCameraCharacteristics = mOneCameraManager.getOneCameraCharacteristics(cameraId);
+ return mCameraCharacteristics != null;
+ }
+ } catch (OneCameraAccessException ignored) { }
+ mAppController.getFatalErrorHandler().onGenericCameraAccessFailure();
+ return false;
}
@Override
public void init(CameraActivity activity, boolean isSecureCamera, boolean isCaptureIntent) {
Profile guard = mProfiler.create("CaptureModule.init").start();
- Log.d(TAG, "init");
+ Log.d(TAG, "init UseAutotransformUiLayout = " + USE_AUTOTRANSFORM_UI_LAYOUT);
HandlerThread thread = new HandlerThread("CaptureModule.mCameraHandler");
thread.start();
mCameraHandler = new Handler(thread.getLooper());
- mCameraManager = mAppController.getCameraManager();
+ mOneCameraOpener = mAppController.getCameraOpener();
+
+ try {
+ mOneCameraManager = OneCameraModule.provideOneCameraManager();
+ } catch (OneCameraException e) {
+ Log.e(TAG, "Unable to provide a OneCameraManager. ", e);
+ }
mDisplayRotation = CameraUtil.getDisplayRotation();
mCameraFacing = getFacingFromCameraId(
mSettingsManager.getInteger(mAppController.getModuleScope(), Keys.KEY_CAMERA_ID));
- updateCameraCharacteristics();
+ mShowErrorAndFinish = !updateCameraCharacteristics();
+ if (mShowErrorAndFinish) {
+ return;
+ }
mUI = new CaptureModuleUI(activity, mAppController.getModuleLayoutRoot(), mUIListener);
mAppController.setPreviewStatusListener(mPreviewStatusListener);
synchronized (mSurfaceTextureLock) {
@Override
public void onShutterButtonLongPressed() {
try {
- CaptureSession session = createAndStartCaptureSession();
-
OneCameraCharacteristics cameraCharacteristics;
- cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraFacing);
+ CameraId cameraId = mOneCameraManager.findFirstCameraFacing(mCameraFacing);
+ cameraCharacteristics = mOneCameraManager.getOneCameraCharacteristics(cameraId);
DeviceOrientation deviceOrientation = mAppController.getOrientationManager()
.getDeviceOrientation();
ImageRotationCalculator imageRotationCalculator = ImageRotationCalculatorImpl
.from(mAppController.getOrientationManager(), cameraCharacteristics);
- mBurstController.startBurst(session,
+ mBurstController.startBurst(
+ new CaptureSession.CaptureSessionCreator() {
+ @Override
+ public CaptureSession createAndStartEmpty() {
+ return createAndStartUntrackedCaptureSession();
+ }
+ },
deviceOrientation,
mCamera.getDirection(),
imageRotationCalculator.toImageRotation().getDegrees());
@Override
public void onShutterCoordinate(TouchCoordinate coord) {
- // TODO Auto-generated method stub
+ mLastShutterTouchCoordinate = coord;
}
@Override
}
}
+
+ private void decorateSessionAtCaptureTime(CaptureSession session) {
+ String flashSetting =
+ mSettingsManager.getString(mAppController.getCameraScope(),
+ Keys.KEY_FLASH_MODE);
+ boolean gridLinesOn = Keys.areGridLinesOn(mSettingsManager);
+ float timerDuration = mSettingsManager
+ .getInteger(SettingsManager.SCOPE_GLOBAL, Keys.KEY_COUNTDOWN_DURATION);
+
+ session.getCollector().decorateAtTimeCaptureRequest(
+ eventprotos.NavigationChange.Mode.PHOTO_CAPTURE,
+ session.getTitle() + ".jpg",
+ (mCameraFacing == Facing.FRONT),
+ mHdrSceneEnabled,
+ mZoomValue,
+ flashSetting,
+ gridLinesOn,
+ timerDuration,
+ mLastShutterTouchCoordinate,
+ null /* TODO: Implement Volume Button Shutter Click Instrumentation */,
+ mCameraCharacteristics.getSensorInfoActiveArraySize()
+ );
+ }
+
private void takePictureNow() {
+ if (mCamera == null) {
+ Log.i(TAG, "Not taking picture since Camera is closed.");
+ return;
+ }
+
CaptureSession session = createAndStartCaptureSession();
int orientation = mAppController.getOrientationManager().getDeviceOrientation()
.getDegrees();
session.getTitle(), orientation, session.getLocation(),
mContext.getExternalCacheDir(), this, mPictureSaverCallback,
mHeadingSensor.getCurrentHeading(), mZoomValue, 0);
+ decorateSessionAtCaptureTime(session);
mCamera.takePicture(params, session);
}
String title = CameraUtil.instance().createJpegName(sessionTime);
CaptureSession session = getServices().getCaptureSessionManager()
.createNewSession(title, sessionTime, location);
- session.startEmpty(new Size((int) mPreviewArea.width(), (int) mPreviewArea.height()));
+
+ session.startEmpty(new CaptureStats(mHdrPlusEnabled),
+ new Size((int) mPreviewArea.width(), (int) mPreviewArea.height()));
+ return session;
+ }
+
+ private CaptureSession createAndStartUntrackedCaptureSession() {
+ long sessionTime = getSessionTime();
+ Location location = mLocationManager.getCurrentLocation();
+ String title = CameraUtil.instance().createJpegName(sessionTime);
+ CaptureSession session = getServices().getCaptureSessionManager()
+ .createNewSession(title, sessionTime, location);
+
+ session.startEmpty(null,
+ new Size((int) mPreviewArea.width(), (int) mPreviewArea.height()));
return session;
}
// Cancel on-going countdown.
mUI.cancelCountDown();
}
- mAppController.getCameraAppUI().showModeOptions();
- mAppController.getCameraAppUI().transitionToCapture();
+
+ if (!mPaused) {
+ mAppController.getCameraAppUI().showModeOptions();
+ mAppController.getCameraAppUI().transitionToCapture();
+ }
}
@Override
}
@Override
- public String getModuleStringIdentifier() {
- return PHOTO_MODULE_STRING_ID;
- }
-
- @Override
public void resume() {
+ if (mShowErrorAndFinish) {
+ return;
+ }
Profile guard = mProfiler.create("CaptureModule.resume").start();
// We'll transition into 'ready' once the preview is started.
mAppController.addPreviewAreaSizeChangedListener(mPreviewAreaChangedListener);
mAppController.addPreviewAreaSizeChangedListener(mUI);
- mAppController.getCameraAppUI().onChangeCamera();
-
guard.mark();
getServices().getRemoteShutterListener().onModuleReady(this);
guard.mark("getRemoteShutterListener.onModuleReady");
// state, ... ).
mAppController.getCameraAppUI().enableModeOptions();
mAppController.setShutterEnabled(true);
+ mAppController.getCameraAppUI().showAccessibilityZoomUI(
+ mCameraCharacteristics.getAvailableMaxDigitalZoom());
mHdrPlusEnabled = mStickyGcamCamera || mAppController.getSettingsManager().getInteger(
SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_HDR_PLUS) == 1;
@Override
public void pause() {
+ if (mShowErrorAndFinish) {
+ return;
+ }
+ cancelCountDown();
mPaused = true;
mHeadingSensor.deactivate();
mAppController.removePreviewAreaSizeChangedListener(mPreviewAreaChangedListener);
getServices().getRemoteShutterListener().onModuleExit();
mBurstController.release();
- cancelCountDown();
closeCamera();
resetTextureBufferSize();
mSoundPlayer.unloadSound(R.raw.timer_final_second);
// facing.
settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_HDR_PLUS, true);
settingsManager.set(mAppController.getModuleScope(), Keys.KEY_CAMERA_ID,
- getBackFacingCameraId());
+ mOneCameraManager.findFirstCameraFacing(Facing.BACK).getValue());
}
}
@Override
public boolean isHdrSupported() {
- return mCameraCharacteristics.isHdrSceneSupported();
+ if (ApiHelper.IS_NEXUS_4 && is16by9AspectRatio(mPictureSize)) {
+ Log.v(TAG, "16:9 N4, no HDR support");
+ return false;
+ } else {
+ return mCameraCharacteristics.isHdrSceneSupported();
+ }
}
@Override
public boolean isHdrPlusSupported() {
- return GcamHelper.hasGcamCapture(mAppController.getCameraFeatureConfig());
+ OneCameraFeatureConfig featureConfig = mAppController.getCameraFeatureConfig();
+ return featureConfig.getHdrPlusSupportLevel(mCameraFacing) !=
+ OneCameraFeatureConfig.HdrPlusSupportLevel.NONE;
}
@Override
bottomBarSpec.enableGridLines = true;
bottomBarSpec.enableCamera = true;
bottomBarSpec.cameraCallback = getCameraCallback();
- bottomBarSpec.enableHdr = hardwareSpec.isHdrSupported() || hardwareSpec.isHdrPlusSupported();
+ bottomBarSpec.enableHdr =
+ hardwareSpec.isHdrSupported() || hardwareSpec.isHdrPlusSupported();
bottomBarSpec.hdrCallback = getHdrButtonCallback();
bottomBarSpec.enableSelfTimer = true;
bottomBarSpec.showSelfTimer = true;
+ bottomBarSpec.isExposureCompensationSupported = mCameraCharacteristics
+ .isExposureCompensationSupported();
+ bottomBarSpec.enableExposureCompensation = bottomBarSpec.isExposureCompensationSupported;
// We must read the key from the settings because the button callback
// is not executed until after this method is called.
// Disable flash if this is a sticky gcam camera, or if
// HDR is enabled.
bottomBarSpec.enableFlash = false;
+ // Disable manual exposure if HDR is enabled.
+ bottomBarSpec.enableExposureCompensation = false;
} else {
// If we are not in HDR / GCAM mode, fallback on the
- // flash supported property for this camera.
+ // flash supported property and manual exposure supported property
+ // for this camera.
bottomBarSpec.enableFlash = mCameraCharacteristics.isFlashSupported();
}
- bottomBarSpec.enableExposureCompensation =
- mCameraCharacteristics.isExposureCompensationSupported();
bottomBarSpec.minExposureCompensation =
mCameraCharacteristics.getMinExposureCompensation();
bottomBarSpec.maxExposureCompensation =
Matrix rotationMatrix = new Matrix();
rotationMatrix.setRotate(mDisplayRotation, 0.5f, 0.5f);
rotationMatrix.mapPoints(points);
+
+ // Invert X coordinate on front camera since the display is mirrored.
+ if (mCameraCharacteristics.getCameraDirection() == Facing.FRONT) {
+ points[0] = 1 - points[0];
+ }
+
mCamera.triggerFocusAndMeterAtPoint(points[0], points[1]);
// Log touch (screen coordinates).
startPassiveFocus();
break;
case ACTIVE_SCAN:
+ // Unused, manual scans are triggered via the UI
break;
case PASSIVE_FOCUSED:
case PASSIVE_UNFOCUSED:
- mFocusController.clearFocusIndicator();
+ // Unused
break;
case ACTIVE_FOCUSED:
case ACTIVE_UNFOCUSED:
- mFocusController.clearFocusIndicator();
+ // Unused
break;
}
@Override
public void onReadyStateChanged(boolean readyForCapture) {
- if (!mBurstController.isReady()) {
- return;
- }
-
if (readyForCapture) {
mAppController.getCameraAppUI().enableModeOptions();
}
@Override
public void onPictureTakingFailed() {
+ mAppController.getFatalErrorHandler().onMediaStorageFailure();
}
/**
}
/**
- * TODO: Remove this method once we are in pure CaptureModule land.
- */
- private String getBackFacingCameraId() {
- if (!(mCameraManager instanceof OneCameraManagerImpl)) {
- throw new IllegalStateException("This should never be called with Camera API V1");
- }
- OneCameraManagerImpl manager = (OneCameraManagerImpl) mCameraManager;
- return manager.getFirstBackCameraId();
- }
-
- /**
* @return Depending on whether we're in sticky-HDR mode or not, return the
* proper callback to be used for when the HDR/HDR+ button is
* pressed.
return;
}
+ ButtonManager buttonManager = mAppController.getButtonManager();
+ buttonManager.disableCameraButtonAndBlock();
+
// At the time this callback is fired, the camera id
// has be set to the desired camera.
mSettingsManager.set(mAppController.getModuleScope(), Keys.KEY_CAMERA_ID,
Log.d(TAG, "Start to switch camera. cameraId=" + cameraId);
mCameraFacing = getFacingFromCameraId(cameraId);
- updateCameraCharacteristics();
+ mShowErrorAndFinish = !updateCameraCharacteristics();
switchCamera();
}
};
updatePreviewTransform(incomingWidth, incomingHeight, false);
}
+ /**
+ * Returns whether it is necessary to apply device-specific fix for b/19271661
+ * on the AutoTransform Path, i.e. USE_AUTOTRANSFORM_UI_LAYOUT == true
+ *
+ * @return whether to apply workaround fix for b/19271661
+ */
+ private boolean requiresNexus4SpecificFixFor16By9Previews() {
+ return USE_AUTOTRANSFORM_UI_LAYOUT && ApiHelper.IS_NEXUS_4
+ && is16by9AspectRatio(mPictureSize);
+ }
+
/***
* Update the preview transform based on the new dimensions. TODO: Make work
* with all: aspect ratios/resolutions x screens/cameras.
// Get natural orientation and buffer dimensions
- Matrix transformMatrix = mPreviewTransformCalculator.toTransformMatrix(
- new Size(mScreenWidth, mScreenHeight),
- new Size(mPreviewBufferWidth, mPreviewBufferHeight));
- mAppController.updatePreviewTransform(transformMatrix);
+ if(USE_AUTOTRANSFORM_UI_LAYOUT) {
+ // Use PhotoUI-based AutoTransformation Interface
+ if (mPreviewBufferWidth != 0 && mPreviewBufferHeight != 0) {
+ if (requiresNexus4SpecificFixFor16By9Previews()) {
+ // Force preview size to be 16:9, even though surface is 4:3
+ // Surface content is assumed to be 16:9.
+ mAppController.updatePreviewAspectRatio(16.f / 9.f);
+ } else {
+ mAppController.updatePreviewAspectRatio(
+ mPreviewBufferWidth / (float) mPreviewBufferHeight);
+ }
+ }
+ } else {
+ Matrix transformMatrix = mPreviewTransformCalculator.toTransformMatrix(
+ new Size(mScreenWidth, mScreenHeight),
+ new Size(mPreviewBufferWidth, mPreviewBufferHeight));
+ mAppController.updatePreviewTransform(transformMatrix);
+ }
+ }
+ }
+
+
+ /**
+ * Calculates whether a picture size is 16:9 ratio, regardless of its
+ * orientation.
+ *
+ * @param size the size of the picture to be considered
+ * @return true, if the picture is 16:9; false if it's invalid or size is null
+ */
+ private boolean is16by9AspectRatio(Size size) {
+ if (size == null || size.getWidth() == 0 || size.getHeight() == 0) {
+ return false;
}
+
+ // Normalize aspect ratio to be greater than 1.
+ final float aspectRatio = (size.getHeight() > size.getWidth())
+ ? (size.getHeight() / (float) size.getWidth())
+ : (size.getWidth() / (float) size.getHeight());
+
+ return Math.abs(aspectRatio - (16.f / 9.f)) < 0.001f;
}
/**
Size previewBufferSize = mCamera.pickPreviewSize(mPictureSize, mContext);
mPreviewBufferWidth = previewBufferSize.getWidth();
mPreviewBufferHeight = previewBufferSize.getHeight();
+
+ // Workaround for N4 TextureView/HAL issues b/19271661 for 16:9 preview
+ // streams.
+ if (requiresNexus4SpecificFixFor16By9Previews()) {
+ // Override the preview selection logic to the largest N4 4:3
+ // preview size but pass in 16:9 aspect ratio in
+ // UpdatePreviewAspectRatio later.
+ mPreviewBufferWidth = 1280;
+ mPreviewBufferHeight = 960;
+ }
updatePreviewBufferSize();
}
guard.mark("Acquired mCameraOpenCloseLock");
- if (mCameraManager == null) {
+ if (mOneCameraOpener == null) {
Log.e(TAG, "no available OneCameraManager, showing error dialog");
mCameraOpenCloseLock.release();
- mAppController.showErrorAndFinish(R.string.cannot_connect_camera);
+ mAppController.getFatalErrorHandler().onGenericCameraAccessFailure();
guard.stop("No OneCameraManager");
return;
}
// Only enable GCam on the back camera
boolean useHdr = mHdrPlusEnabled && mCameraFacing == Facing.BACK;
+ CameraId cameraId = mOneCameraManager.findFirstCameraFacing(mCameraFacing);
+ final String settingScope = SettingsManager.getCameraSettingScope(cameraId.getValue());
+
+ OneCameraCaptureSetting captureSetting;
// Read the preferred picture size from the setting.
try {
- mPictureSize = mAppController.getResolutionSetting().getPictureSize(mCameraFacing);
+ mPictureSize = mAppController.getResolutionSetting().getPictureSize(
+ cameraId, mCameraFacing);
+ captureSetting = OneCameraCaptureSetting.create(mPictureSize, mSettingsManager,
+ getHardwareSpec(), settingScope, useHdr);
} catch (OneCameraAccessException ex) {
- mAppController.showErrorAndFinish(R.string.cannot_connect_camera);
+ mAppController.getFatalErrorHandler().onGenericCameraAccessFailure();
return;
}
- mCameraManager.open(mCameraFacing, useHdr, mPictureSize,
- new OpenCallback() {
- @Override
- public void onFailure() {
- Log.e(TAG, "Could not open camera.");
- mCamera = null;
- mCameraOpenCloseLock.release();
- mAppController.showErrorAndFinish(R.string.cannot_connect_camera);
- }
-
- @Override
- public void onCameraClosed() {
- mCamera = null;
- mCameraOpenCloseLock.release();
- }
-
- @Override
- public void onCameraOpened(final OneCamera camera) {
- Log.d(TAG, "onCameraOpened: " + camera);
- mCamera = camera;
- updatePreviewBufferDimension();
-
- // If the surface texture is not destroyed, it may have
- // the last frame lingering. We need to hold off setting
- // transform until preview is started.
- updatePreviewBufferSize();
- mState = ModuleState.WATCH_FOR_NEXT_FRAME_AFTER_PREVIEW_STARTED;
- Log.d(TAG, "starting preview ...");
-
- // TODO: make mFocusController final and remove null
- // check.
- if (mFocusController != null) {
- camera.setFocusDistanceListener(mFocusController);
- }
-
- // TODO: Consider rolling these two calls into one.
- camera.startPreview(new Surface(getPreviewSurfaceTexture()),
- new CaptureReadyCallback() {
- @Override
- public void onSetupFailed() {
- // We must release this lock here,
- // before posting to the main handler
- // since we may be blocked in pause(),
- // getting ready to close the camera.
- mCameraOpenCloseLock.release();
- Log.e(TAG, "Could not set up preview.");
- mMainThread.execute(new Runnable() {
- @Override
- public void run() {
- if (mCamera == null) {
- Log.d(TAG, "Camera closed, aborting.");
- return;
- }
- mCamera.close();
- mCamera = null;
- // TODO: Show an error message
- // and exit.
+ mOneCameraOpener.open(cameraId, captureSetting, mCameraHandler, mainThread,
+ imageRotationCalculator, mBurstController, mSoundPlayer,
+ new OpenCallback() {
+ @Override
+ public void onFailure() {
+ Log.e(TAG, "Could not open camera.");
+ // Sometimes the failure happens due to the controller
+ // being in paused state but mCamera is already
+ // initialized. In these cases we just need to close the
+ // camera device without showing the error dialog.
+ // Application will properly reopen the camera on the next
+ // resume operation (b/21025113).
+ boolean isControllerPaused = mAppController.isPaused();
+ if (mCamera != null) {
+ mCamera.close();
+ }
+ mCamera = null;
+ mCameraOpenCloseLock.release();
+ if (!isControllerPaused) {
+ mAppController.getFatalErrorHandler().onCameraOpenFailure();
+ }
+ }
+
+ @Override
+ public void onCameraClosed() {
+ mCamera = null;
+ mCameraOpenCloseLock.release();
+ }
+
+ @Override
+ public void onCameraOpened(@Nonnull final OneCamera camera) {
+ Log.d(TAG, "onCameraOpened: " + camera);
+ mCamera = camera;
+
+ // A race condition exists where the camera may be in the process
+ // of opening (blocked), but the activity gets destroyed. If the
+ // preview is initialized or callbacks are invoked on a destroyed
+ // activity, bad things can happen.
+ if (mAppController.isPaused()) {
+ onFailure();
+ return;
+ }
+
+ // When camera is opened, the zoom is implicitly reset to 1.0f
+ mZoomValue = 1.0f;
+
+ updatePreviewBufferDimension();
+
+ // If the surface texture is not destroyed, it may have
+ // the last frame lingering. We need to hold off setting
+ // transform until preview is started.
+ updatePreviewBufferSize();
+ mState = ModuleState.WATCH_FOR_NEXT_FRAME_AFTER_PREVIEW_STARTED;
+ Log.d(TAG, "starting preview ...");
+
+ // TODO: make mFocusController final and remove null
+ // check.
+ if (mFocusController != null) {
+ camera.setFocusDistanceListener(mFocusController);
+ }
+
+ mMainThread.execute(new Runnable() {
+ @Override
+ public void run() {
+ mAppController.getCameraAppUI().onChangeCamera();
+ mAppController.getButtonManager().enableCameraButton();
+ }
+ });
+
+ // TODO: Consider rolling these two calls into one.
+ camera.startPreview(new Surface(getPreviewSurfaceTexture()),
+ new CaptureReadyCallback() {
+ @Override
+ public void onSetupFailed() {
+ // We must release this lock here,
+ // before posting to the main handler
+ // since we may be blocked in pause(),
+ // getting ready to close the camera.
+ mCameraOpenCloseLock.release();
+ Log.e(TAG, "Could not set up preview.");
+ mMainThread.execute(new Runnable() {
+ @Override
+ public void run() {
+ if (mCamera == null) {
+ Log.d(TAG, "Camera closed, aborting.");
+ return;
}
- });
- }
-
- @Override
- public void onReadyForCapture() {
- // We must release this lock here,
- // before posting to the main handler
- // since we may be blocked in pause(),
- // getting ready to close the camera.
- mCameraOpenCloseLock.release();
- mMainThread.execute(new Runnable() {
- @Override
- public void run() {
- Log.d(TAG, "Ready for capture.");
- if (mCamera == null) {
- Log.d(TAG, "Camera closed, aborting.");
- return;
- }
- onPreviewStarted();
- // May be overridden by
- // subsequent call to
- // onReadyStateChanged().
- onReadyStateChanged(true);
- mCamera.setReadyStateChangedListener(
- CaptureModule.this);
- // Enable zooming after preview
- // has started.
- mUI.initializeZoom(mCamera.getMaxZoom());
- mCamera.setFocusStateListener(CaptureModule.this);
+ mCamera.close();
+ mCamera = null;
+ // TODO: Show an error message
+ // and exit.
+ }
+ });
+ }
+
+ @Override
+ public void onReadyForCapture() {
+ // We must release this lock here,
+ // before posting to the main handler
+ // since we may be blocked in pause(),
+ // getting ready to close the camera.
+ mCameraOpenCloseLock.release();
+ mMainThread.execute(new Runnable() {
+ @Override
+ public void run() {
+ Log.d(TAG, "Ready for capture.");
+ if (mCamera == null) {
+ Log.d(TAG, "Camera closed, aborting.");
+ return;
}
- });
- }
- });
- }
- }, mCameraHandler, mainThread, imageRotationCalculator, mBurstController);
- guard.stop("mCameraManager.open()");
+ onPreviewStarted();
+ // May be overridden by
+ // subsequent call to
+ // onReadyStateChanged().
+ onReadyStateChanged(true);
+ mCamera.setReadyStateChangedListener(
+ CaptureModule.this);
+ // Enable zooming after preview
+ // has started.
+ mUI.initializeZoom(mCamera.getMaxZoom());
+ mCamera.setFocusStateListener(CaptureModule.this);
+ }
+ });
+ }
+ });
+ }
+ }, mAppController.getFatalErrorHandler());
+ guard.stop("mOneCameraOpener.open()");
}
private void closeCamera() {
* Re-initialize the camera if e.g. the HDR mode or facing property changed.
*/
private void switchCamera() {
+ if (mShowErrorAndFinish) {
+ return;
+ }
if (mPaused) {
return;
}
initSurfaceTextureConsumer();
}
- private int getPreviewOrientation(int deviceOrientationDegrees) {
- // Important: Camera2 buffers are already rotated to the natural
- // orientation of the device (at least for the back-camera).
-
- return (360 - deviceOrientationDegrees) % 360;
- }
-
/**
* Returns which way around the camera is facing, based on it's ID.
* <p>