There is a small chance that the activity can be destroyed
between the time the camera is created and the preview is started.
This can lead to unchecked NPE's across the app because most code
assumes that there will never be a case where activity objects
are accessed after onDestroy.
Bug:
20097425
Change-Id: I2904ffba451ded2417a806c83fd12e4f62611150
unregisterReceiver(mShutdownReceiver);
}
unregisterReceiver(mShutdownReceiver);
}
+ // Ensure anything that checks for "isPaused" returns true.
+ mPaused = true;
+
mSettingsManager.removeAllListeners();
mCameraController.removeCallbackReceiver();
mCameraController.setCameraExceptionHandler(null);
mSettingsManager.removeAllListeners();
mCameraController.removeCallbackReceiver();
mCameraController.setCameraExceptionHandler(null);
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
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.
/**
* New Capture module that is made to support photo and video capture on top of
* the OneCamera API, to transparently support GCam.
- public void onCameraOpened(final OneCamera camera) {
+ public void onCameraOpened(@Nonnull final OneCamera camera) {
Log.d(TAG, "onCameraOpened: " + camera);
mCamera = 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;
// When camera is opened, the zoom is implicitly reset to 1.0f
mZoomValue = 1.0f;
import com.android.camera.captureintent.stateful.Event;
import com.android.camera.one.OneCamera;
import com.android.camera.captureintent.stateful.Event;
import com.android.camera.one.OneCamera;
+import javax.annotation.Nonnull;
+
public class EventOnOpenCameraSucceeded implements Event {
private final OneCamera mCamera;
public class EventOnOpenCameraSucceeded implements Event {
private final OneCamera mCamera;
- public EventOnOpenCameraSucceeded(OneCamera camera) {
+ public EventOnOpenCameraSucceeded(@Nonnull OneCamera camera) {
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
+import javax.annotation.Nonnull;
+
/**
* Represents a state that the module is waiting for a camera to be opened.
*/
/**
* Represents a state that the module is waiting for a camera to be opened.
*/
- public void onCameraOpened(final OneCamera camera) {
+ public void onCameraOpened(@Nonnull final OneCamera camera) {
getStateMachine().processEvent(new EventOnOpenCameraSucceeded(camera));
}
};
getStateMachine().processEvent(new EventOnOpenCameraSucceeded(camera));
}
};
*
* @param camera the camera instance that was successfully opened
*/
*
* @param camera the camera instance that was successfully opened
*/
- public void onCameraOpened(OneCamera camera);
+ public void onCameraOpened(@Nonnull OneCamera camera);
/**
* Called if opening the camera failed.
/**
* Called if opening the camera failed.
imageRotationCalculator,
burstController,
soundPlayer, fatalErrorHandler);
imageRotationCalculator,
burstController,
soundPlayer, fatalErrorHandler);
- openCallback.onCameraOpened(oneCamera);
+
+ if (oneCamera != null) {
+ openCallback.onCameraOpened(oneCamera);
+ } else {
+ Log.d(TAG, "Could not construct a OneCamera object!");
+ openCallback.onFailure();
+ }
} catch (CameraAccessException e) {
Log.d(TAG, "Could not get camera characteristics", e);
openCallback.onFailure();
} catch (CameraAccessException e) {
Log.d(TAG, "Could not get camera characteristics", e);
openCallback.onFailure();