diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 53861ab0e..f783db266 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,7 +16,7 @@ + android:required="false" /> diff --git a/app/src/main/java/protect/card_locker/CatimaCaptureManager.java b/app/src/main/java/protect/card_locker/CatimaCaptureManager.java index 7507d8090..e083c48ff 100644 --- a/app/src/main/java/protect/card_locker/CatimaCaptureManager.java +++ b/app/src/main/java/protect/card_locker/CatimaCaptureManager.java @@ -4,22 +4,24 @@ import android.app.Activity; import android.content.Context; import android.widget.Toast; +import androidx.core.util.Consumer; + import com.journeyapps.barcodescanner.CaptureManager; import com.journeyapps.barcodescanner.DecoratedBarcodeView; public class CatimaCaptureManager extends CaptureManager { - private final Context mContext; + private final Consumer mErrorCallback; - public CatimaCaptureManager(Activity activity, DecoratedBarcodeView barcodeView) { + public CatimaCaptureManager(Activity activity, DecoratedBarcodeView barcodeView, Consumer errorCallback) { super(activity, barcodeView); - mContext = activity.getApplicationContext(); + mErrorCallback = errorCallback; } @Override protected void displayFrameworkBugMessageAndExit(String message) { // We don't want to exit, as we also have a enter from card image and add manually button here - // So we show a toast instead - Toast.makeText(mContext, message, Toast.LENGTH_LONG).show(); + // So, instead, we call our error callback + mErrorCallback.accept(message); } } diff --git a/app/src/main/java/protect/card_locker/ScanActivity.java b/app/src/main/java/protect/card_locker/ScanActivity.java index 9679751bb..9c177751e 100644 --- a/app/src/main/java/protect/card_locker/ScanActivity.java +++ b/app/src/main/java/protect/card_locker/ScanActivity.java @@ -78,6 +78,7 @@ public class ScanActivity extends CatimaAppCompatActivity { static final String STATE_SCANNER_ACTIVE = "scannerActive"; private boolean mScannerActive = true; + private boolean mHasError = false; private void extractIntentFields(Intent intent) { final Bundle b = intent.getExtras(); @@ -141,7 +142,7 @@ public class ScanActivity extends CatimaAppCompatActivity { // Even though we do the actual decoding with the barcodeScannerView // CaptureManager needs to be running to show the camera and scanning bar - capture = new CatimaCaptureManager(this, barcodeScannerView); + capture = new CatimaCaptureManager(this, barcodeScannerView, this::onCaptureManagerError); Intent captureIntent = new Intent(); Bundle captureIntentBundle = new Bundle(); captureIntentBundle.putBoolean(Intents.Scan.BEEP_ENABLED, false); @@ -178,9 +179,14 @@ public class ScanActivity extends CatimaAppCompatActivity { capture.onResume(); } - if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { - showCameraPermissionMissingText(false); + if (!Utils.deviceHasCamera(this)) { + showCameraError(getString(R.string.noCameraFoundGuideText), false); + } else if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + showCameraPermissionMissingText(); + } else { + hideCameraError(); } + scaleScreen(); } @@ -402,12 +408,37 @@ public class ScanActivity extends CatimaAppCompatActivity { } } - private void showCameraPermissionMissingText(boolean show) { - customBarcodeScannerBinding.cameraPermissionDeniedLayout.cameraPermissionDeniedClickableArea.setOnClickListener(show ? v -> { + public void onCaptureManagerError(String errorMessage) { + if (mHasError) { + // We're already showing an error, ignore this new error + return; + } + + showCameraError(errorMessage, false); + } + + private void showCameraPermissionMissingText() { + showCameraError(getString(R.string.noCameraPermissionDirectToSystemSetting), true); + } + + private void showCameraError(String message, boolean setOnClick) { + customBarcodeScannerBinding.cameraErrorLayout.cameraErrorMessage.setText(message); + + setCameraErrorState(true, setOnClick); + } + + private void hideCameraError() { + setCameraErrorState(false, false); + } + + private void setCameraErrorState(boolean visible, boolean setOnClick) { + mHasError = visible; + + customBarcodeScannerBinding.cameraErrorLayout.cameraErrorClickableArea.setOnClickListener(visible && setOnClick ? v -> { navigateToSystemPermissionSetting(); } : null); - customBarcodeScannerBinding.cardInputContainer.setBackgroundColor(show ? obtainThemeAttribute(com.google.android.material.R.attr.colorSurface) : Color.TRANSPARENT); - customBarcodeScannerBinding.cameraPermissionDeniedLayout.getRoot().setVisibility(show ? View.VISIBLE : View.GONE); + customBarcodeScannerBinding.cardInputContainer.setBackgroundColor(visible ? obtainThemeAttribute(com.google.android.material.R.attr.colorSurface) : Color.TRANSPARENT); + customBarcodeScannerBinding.cameraErrorLayout.getRoot().setVisibility(visible ? View.VISIBLE : View.GONE); } private void scaleScreen() { @@ -417,8 +448,8 @@ public class ScanActivity extends CatimaAppCompatActivity { float mediumSizePx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,MEDIUM_SCALE_FACTOR_DIP,getResources().getDisplayMetrics()); boolean shouldScaleSmaller = screenHeight < mediumSizePx; - customBarcodeScannerBinding.cameraPermissionDeniedLayout.cameraPermissionDeniedIcon.setVisibility(shouldScaleSmaller ? View.GONE : View.VISIBLE); - customBarcodeScannerBinding.cameraPermissionDeniedLayout.cameraPermissionDeniedTitle.setVisibility(shouldScaleSmaller ? View.GONE : View.VISIBLE); + customBarcodeScannerBinding.cameraErrorLayout.cameraErrorIcon.setVisibility(shouldScaleSmaller ? View.GONE : View.VISIBLE); + customBarcodeScannerBinding.cameraErrorLayout.cameraErrorTitle.setVisibility(shouldScaleSmaller ? View.GONE : View.VISIBLE); } private int obtainThemeAttribute(int attribute) { @@ -444,7 +475,11 @@ public class ScanActivity extends CatimaAppCompatActivity { boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; if (requestCode == CaptureManager.getCameraPermissionReqCode()) { - showCameraPermissionMissingText(!granted); + if (granted) { + hideCameraError(); + } else { + showCameraPermissionMissingText(); + } } else if (requestCode == PERMISSION_SCAN_ADD_FROM_IMAGE || requestCode == PERMISSION_SCAN_ADD_FROM_PDF) { if (granted) { if (requestCode == PERMISSION_SCAN_ADD_FROM_IMAGE) { diff --git a/app/src/main/java/protect/card_locker/Utils.java b/app/src/main/java/protect/card_locker/Utils.java index 7402468b9..eb3ef6bf1 100644 --- a/app/src/main/java/protect/card_locker/Utils.java +++ b/app/src/main/java/protect/card_locker/Utils.java @@ -13,6 +13,8 @@ import android.graphics.Color; import android.graphics.ImageDecoder; import android.graphics.Matrix; import android.graphics.pdf.PdfRenderer; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraManager; import android.net.Uri; import android.os.Build; import android.os.ParcelFileDescriptor; @@ -1015,4 +1017,12 @@ public class Utils { return false; }); } + + public static boolean deviceHasCamera(Context context) { + try { + return ((CameraManager) context.getSystemService(Context.CAMERA_SERVICE)).getCameraIdList().length > 0; + } catch (CameraAccessException e) { + return false; + } + } } diff --git a/app/src/main/res/drawable/camera_permission_denied.xml b/app/src/main/res/drawable/camera_error.xml similarity index 100% rename from app/src/main/res/drawable/camera_permission_denied.xml rename to app/src/main/res/drawable/camera_error.xml diff --git a/app/src/main/res/layout/camera_permission_failed_layout.xml b/app/src/main/res/layout/camera_error_layout.xml similarity index 76% rename from app/src/main/res/layout/camera_permission_failed_layout.xml rename to app/src/main/res/layout/camera_error_layout.xml index 2d47929a6..8e3d823ea 100644 --- a/app/src/main/res/layout/camera_permission_failed_layout.xml +++ b/app/src/main/res/layout/camera_error_layout.xml @@ -9,20 +9,20 @@ tools:showIn="@layout/custom_barcode_scanner"> + android:src="@drawable/camera_error" /> + android:text="@string/zxing_msg_camera_framework_bug" /> diff --git a/app/src/main/res/layout/custom_barcode_scanner.xml b/app/src/main/res/layout/custom_barcode_scanner.xml index d197ffde5..3ab8c96a0 100644 --- a/app/src/main/res/layout/custom_barcode_scanner.xml +++ b/app/src/main/res/layout/custom_barcode_scanner.xml @@ -34,8 +34,8 @@ android:padding="@dimen/activity_scanner_padding"> Could not find a supported file manager Which of the found barcodes do you want to use? Page %d + Your device does not seem to have a camera. If it does, try rebooting the device. Otherwise, use the "More options" button below to add a barcode another way.