From 6a5aa089ae4ee9a8ad0717d6e306093a2bf09ba3 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Tue, 7 Sep 2021 16:03:12 -0300 Subject: [PATCH] Fix crash if sensors disabled in developer mode. --- .../camera/view/SignalCameraView.java | 25 ++++++++++++++++--- .../camera/view/SignalCameraXModule.java | 9 +++++-- .../securesms/mediasend/CameraXFragment.java | 14 +++++++++-- app/src/main/res/values/strings.xml | 1 + 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/androidx/camera/view/SignalCameraView.java b/app/src/main/java/androidx/camera/view/SignalCameraView.java index e8a433453c..37c94e9b30 100644 --- a/app/src/main/java/androidx/camera/view/SignalCameraView.java +++ b/app/src/main/java/androidx/camera/view/SignalCameraView.java @@ -60,6 +60,7 @@ import androidx.camera.core.impl.LensFacingConverter; import androidx.camera.core.impl.utils.executor.CameraXExecutors; import androidx.camera.core.impl.utils.futures.FutureCallback; import androidx.camera.core.impl.utils.futures.Futures; +import androidx.core.util.Consumer; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LiveData; @@ -130,6 +131,11 @@ public final class SignalCameraView extends FrameLayout { // For accessibility event private MotionEvent mUpEvent; + // BEGIN Custom Signal Code Block + private Consumer errorConsumer; + private Throwable pendingError; + // END Custom Signal Code Block + public SignalCameraView(@NonNull Context context) { this(context, null); } @@ -167,20 +173,33 @@ public final class SignalCameraView extends FrameLayout { * androidx.lifecycle.Lifecycle.State#DESTROYED} state. * @throws IllegalStateException if camera permissions are not granted. */ + // BEGIN Custom Signal Code Block + @RequiresPermission(permission.CAMERA) - public void bindToLifecycle(@NonNull LifecycleOwner lifecycleOwner) { + public void bindToLifecycle(@NonNull LifecycleOwner lifecycleOwner, Consumer errorConsumer) { mCameraModule.bindToLifecycle(lifecycleOwner); + this.errorConsumer = errorConsumer; + if (pendingError != null) { + errorConsumer.accept(pendingError); + } } + // END Custom Signal Code Block + private void init(Context context, @Nullable AttributeSet attrs) { addView(mPreviewView = new PreviewView(getContext()), 0 /* view position */); // Begin custom signal code block mPreviewView.setImplementationMode(PreviewView.ImplementationMode.COMPATIBLE); + mCameraModule = new SignalCameraXModule(this, error -> { + if (errorConsumer != null) { + errorConsumer.accept(error); + } else { + pendingError = error; + } + }); // End custom signal code block - mCameraModule = new SignalCameraXModule(this); - if (attrs != null) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraView); setScaleType( diff --git a/app/src/main/java/androidx/camera/view/SignalCameraXModule.java b/app/src/main/java/androidx/camera/view/SignalCameraXModule.java index ea719b7c17..4cad6d5adb 100644 --- a/app/src/main/java/androidx/camera/view/SignalCameraXModule.java +++ b/app/src/main/java/androidx/camera/view/SignalCameraXModule.java @@ -46,6 +46,7 @@ import androidx.camera.core.impl.utils.executor.CameraXExecutors; import androidx.camera.core.impl.utils.futures.FutureCallback; import androidx.camera.core.impl.utils.futures.Futures; import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.core.util.Consumer; import androidx.core.util.Preconditions; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; @@ -123,7 +124,9 @@ final class SignalCameraXModule { @Nullable ProcessCameraProvider mCameraProvider; - SignalCameraXModule(SignalCameraView view) { + // BEGIN Custom Signal Code Block + SignalCameraXModule(SignalCameraView view, Consumer errorConsumer) { + // END Custom Signal Code Block mCameraView = view; Futures.addCallback(ProcessCameraProvider.getInstance(view.getContext()), @@ -141,7 +144,9 @@ final class SignalCameraXModule { @Override public void onFailure(Throwable t) { - throw new RuntimeException("CameraX failed to initialize.", t); + // BEGIN Custom Signal Code Block + errorConsumer.accept(t); + // END Custom Signal Code Block } }, CameraXExecutors.mainThreadExecutor()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java index e53ec3572f..d41d7900bc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java @@ -18,6 +18,7 @@ import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.RotateAnimation; import android.widget.ImageView; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -118,7 +119,7 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { this.controlsContainer = view.findViewById(R.id.camerax_controls_container); camera.setScaleType(PreviewView.ScaleType.FIT_CENTER); - camera.bindToLifecycle(getViewLifecycleOwner()); + camera.bindToLifecycle(getViewLifecycleOwner(), this::handleCameraInitializationError); camera.setCameraLensFacing(CameraXUtil.toLensFacing(TextSecurePreferences.getDirectCaptureCameraId(requireContext()))); onOrientationChanged(getResources().getConfiguration().orientation); @@ -147,7 +148,7 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { public void onResume() { super.onResume(); - camera.bindToLifecycle(getViewLifecycleOwner()); + camera.bindToLifecycle(getViewLifecycleOwner(), this::handleCameraInitializationError); requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); } @@ -195,6 +196,15 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { }); } + private void handleCameraInitializationError(Throwable error) { + Log.w(TAG, "An error occurred", error); + + Context context = getActivity(); + if (context != null) { + Toast.makeText(context, R.string.CameraFragment__failed_to_open_camera, Toast.LENGTH_SHORT).show(); + } + } + private void onOrientationChanged(int orientation) { int layout = orientation == Configuration.ORIENTATION_PORTRAIT ? R.layout.camera_controls_portrait : R.layout.camera_controls_landscape; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9c16242fb1..4fb18baf98 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3813,6 +3813,7 @@ View once message You\'ll lose any changes you\'ve made to this photo. Delete + Failed to open camera