Skip to content

Commit 18d9347

Browse files
committed
improve camera2 to camera1 fallback on legacy devices.
1 parent 0911852 commit 18d9347

File tree

2 files changed

+58
-38
lines changed

2 files changed

+58
-38
lines changed

android/src/main/java/com/google/android/cameraview/Camera2.java

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ public void onSurfaceDestroyed() {
305305
boolean start() {
306306
if (!chooseCameraIdByFacing()) {
307307
mAspectRatio = mInitialRatio;
308+
mCallback.onMountError();
308309
return false;
309310
}
310311
collectCameraInfo();
@@ -731,6 +732,33 @@ void setDeviceOrientation(int deviceOrientation) {
731732
//mPreview.setDisplayOrientation(deviceOrientation); // this is not needed and messes up the display orientation
732733
}
733734

735+
736+
// This is a helper method to query Camera2 legacy status so we don't need
737+
// to instantiate and set all its props in order to check if it is legacy or not
738+
// and then fallback to Camera1. This way, legacy devices can fall back to Camera1 right away
739+
// This method makes sure all cameras are not legacy, so further checks are not needed.
740+
public static boolean isLegacy(Context context){
741+
try{
742+
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
743+
String[] ids = manager.getCameraIdList();
744+
for (String id : ids) {
745+
CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
746+
Integer level = characteristics.get(
747+
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
748+
if (level == null ||
749+
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
750+
Log.w(TAG, "Camera2 can only run in legacy mode and should not be used.");
751+
return true;
752+
}
753+
}
754+
return false;
755+
}
756+
catch(CameraAccessException ex){
757+
Log.e(TAG, "Failed to check camera legacy status, returning true.", ex);
758+
return true;
759+
}
760+
}
761+
734762
/**
735763
* <p>Chooses a camera ID by the specified camera facing ({@link #mFacing}).</p>
736764
* <p>This rewrites {@link #mCameraId}, {@link #mCameraCharacteristics}, and optionally
@@ -742,19 +770,16 @@ private boolean chooseCameraIdByFacing() {
742770
int internalFacing = INTERNAL_FACINGS.get(mFacing);
743771
final String[] ids = mCameraManager.getCameraIdList();
744772
if (ids.length == 0) { // No camera
745-
throw new RuntimeException("No camera available.");
773+
Log.e(TAG, "No cameras available.");
774+
return false;
746775
}
747776
for (String id : ids) {
748777
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
749-
Integer level = characteristics.get(
750-
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
751-
if (level == null ||
752-
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
753-
continue;
754-
}
778+
755779
Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING);
756780
if (internal == null) {
757-
throw new NullPointerException("Unexpected state: LENS_FACING null");
781+
Log.e(TAG, "Unexpected state: LENS_FACING null");
782+
continue;
758783
}
759784
if (internal == internalFacing) {
760785
mCameraId = id;
@@ -765,15 +790,11 @@ private boolean chooseCameraIdByFacing() {
765790
// Not found
766791
mCameraId = ids[0];
767792
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
768-
Integer level = mCameraCharacteristics.get(
769-
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
770-
if (level == null ||
771-
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
772-
return false;
773-
}
793+
774794
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
775795
if (internal == null) {
776-
throw new NullPointerException("Unexpected state: LENS_FACING null");
796+
Log.e(TAG, "Unexpected state: LENS_FACING null");
797+
return false;
777798
}
778799
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) {
779800
if (INTERNAL_FACINGS.valueAt(i) == internal) {
@@ -786,7 +807,8 @@ private boolean chooseCameraIdByFacing() {
786807
mFacing = Constants.FACING_BACK;
787808
return true;
788809
} catch (CameraAccessException e) {
789-
throw new RuntimeException("Failed to get a list of camera devices", e);
810+
Log.e(TAG, "Failed to get a list of camera devices", e);
811+
return false;
790812
}
791813
}
792814
else{
@@ -796,17 +818,11 @@ private boolean chooseCameraIdByFacing() {
796818
// for legacy hardware
797819
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(_mCameraId);
798820

799-
Integer level = mCameraCharacteristics.get(
800-
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
801-
if (level == null ||
802-
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
803-
return false;
804-
}
805-
806821
// set our facing variable so orientation also works as expected
807822
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
808823
if (internal == null) {
809-
throw new NullPointerException("Unexpected state: LENS_FACING null");
824+
Log.e(TAG, "Unexpected state: LENS_FACING null");
825+
return false;
810826
}
811827
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) {
812828
if (INTERNAL_FACINGS.valueAt(i) == internal) {
@@ -819,7 +835,8 @@ private boolean chooseCameraIdByFacing() {
819835
return true;
820836
}
821837
catch(Exception e){
822-
throw new RuntimeException("Failed to get camera characteristics", e);
838+
Log.e(TAG, "Failed to get camera characteristics", e);
839+
return false;
823840
}
824841
}
825842
}

android/src/main/java/com/google/android/cameraview/CameraView.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public CameraView(Context context, AttributeSet attrs, int defStyleAttr, boolean
126126
// Internal setup
127127
final PreviewImpl preview = createPreviewImpl(context);
128128
mCallbacks = new CallbackBridge();
129-
if (fallbackToOldApi || Build.VERSION.SDK_INT < 21) {
129+
if (fallbackToOldApi || Build.VERSION.SDK_INT < 21 || Camera2.isLegacy(context)) {
130130
mImpl = new Camera1(mCallbacks, preview, mBgHandler);
131131
} else if (Build.VERSION.SDK_INT < 23) {
132132
mImpl = new Camera2(mCallbacks, preview, context, mBgHandler);
@@ -292,7 +292,7 @@ public void setUsingCamera2Api(boolean useCamera2) {
292292
boolean wasOpened = isCameraOpened();
293293
Parcelable state = onSaveInstanceState();
294294

295-
if (useCamera2) {
295+
if (useCamera2 && !Camera2.isLegacy(mContext)) {
296296
if (wasOpened) {
297297
stop();
298298
}
@@ -323,17 +323,20 @@ public void setUsingCamera2Api(boolean useCamera2) {
323323
* {@link Activity#onResume()}.
324324
*/
325325
public void start() {
326-
if (!mImpl.start()) {
327-
if (mImpl.getView() != null) {
328-
this.removeView(mImpl.getView());
329-
}
330-
//store the state and restore this state after fall back to Camera1
331-
Parcelable state = onSaveInstanceState();
332-
// Camera2 uses legacy hardware layer; fall back to Camera1
333-
mImpl = new Camera1(mCallbacks, createPreviewImpl(getContext()), mBgHandler);
334-
onRestoreInstanceState(state);
335-
mImpl.start();
336-
}
326+
mImpl.start();
327+
328+
// this fallback is no longer needed and was too buggy/slow
329+
// if (!mImpl.start()) {
330+
// if (mImpl.getView() != null) {
331+
// this.removeView(mImpl.getView());
332+
// }
333+
// //store the state and restore this state after fall back to Camera1
334+
// Parcelable state = onSaveInstanceState();
335+
// // Camera2 uses legacy hardware layer; fall back to Camera1
336+
// mImpl = new Camera1(mCallbacks, createPreviewImpl(getContext()), mBgHandler);
337+
// onRestoreInstanceState(state);
338+
// mImpl.start();
339+
// }
337340
}
338341

339342
/**

0 commit comments

Comments
 (0)