android – Barcode scanner not working 2nd time activity launched

I am building barcode scanning functionality into an app, and have followed this guide: https://learntodroid.com/how-to-create-a-qr-code-scanner-app-in-android/.

I have a main activity, which launches my QR scanning activity. When I detect a particular uri from the QR code (based on scheme, host and path), I want to end the QR scanning activity, return to my main activity and launch a dialog.

This is all working – the first time. However, if I release the scanning activity, it no longer detects QR codes, and my onQRCodeFound never gets hit. (Killing and restarting the app resets it, I can scan 1 QR code successfully again, but then it stops detecting them if I reopen the QR activity). The image preview is shown, but the QR never gets recognised.

I do get W/System.err: com.google.zxing.NotFoundException printed to the log repeatedly while the activity is open.

UPDATE
On more investigation I found that on the 2nd (and subsequent times) I launch this activity the previewView has a width and height of 0 (the first time, it’s correctly getting the size of 1080×2280). Setting a target resolution of 0x0 for the ImageAnalysis was the problem.

If I hard code the resolution, rather than using previewView.getWidth() and previewView.getHeight(), then it works fine every time.

If I change the call to bindCameraPreview(cameraProvider) to previewView.post(()->bindCameraPreview(cameraProvider)) it works.

Not sure if this is the best/correct solution, but it’s working for me. I still don’t understand why my previewView has the correct dimensions the first time, and 0s the 2nd – if anyone knows, please enlighten me!

END UPDATE

Here is my ScanQRActivity:

public class ScanQRActivity extends AppCompatActivity {
    private static final int PERMISSION_REQUEST_CAMERA = 0;
    private PreviewView previewView;
    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
    private Button qrCodeFoundButton;
    private String qrCode;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_qr_scan);

        previewView = findViewById(R.id.activity_main_previewView);

        qrCodeFoundButton = findViewById(R.id.activity_main_qrCodeFoundButton);
        qrCodeFoundButton.setVisibility(View.INVISIBLE);

        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        requestCamera();
    }

    private void requestCamera() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            startCamera();
        } else {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
                ActivityCompat.requestPermissions(ScanQRActivity.this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA);
            } else {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA);
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSION_REQUEST_CAMERA) {
            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                startCamera();
            } else {
                // Toast.makeText(this, "Camera Permission Denied", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private void startCamera() {
        cameraProviderFuture.addListener(() -> {
            try {
                ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                bindCameraPreview(cameraProvider);


            } catch (ExecutionException | InterruptedException e) {
                Toast.makeText(this, "Error starting camera " + e.getMessage(), Toast.LENGTH_SHORT).show();
            }
        }, ContextCompat.getMainExecutor(this));
    }

    private void bindCameraPreview(@NonNull ProcessCameraProvider cameraProvider) {
        previewView.setImplementationMode(PreviewView.ImplementationMode.COMPATIBLE);
        Preview preview = new Preview.Builder()
                .build();

        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build();

        preview.setSurfaceProvider(previewView.getSurfaceProvider());

        ImageAnalysis imageAnalysis =
                new ImageAnalysis.Builder()
                        .setTargetResolution(new Size(previewView.getWidth(), previewView.getHeight() ))
                        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                        .build();

        imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this), new QRCodeImageAnalyzer(new QRCodeImageAnalyzer.QRCodeFoundListener() {
            @Override
            public void onQRCodeFound(String _qrCode) {
                qrCode = _qrCode;
                qrCodeFoundButton.setVisibility(View.VISIBLE);
                Uri code = Uri.parse(qrCode);
                if(code.getScheme().equals("myCustomScheme") && code.getHost().equals("app")){
                   String path = code.getPath();
                   String host = code.getHost() ;
                  String query =  code.getQuery();
                  List<String> params = code.getQueryParameters("a");
                  if(path.equals("/voucher")){
                      Intent intent = new Intent();
                      intent.putExtra("type", "voucher");
                      intent.putExtra("voucherCode", code.getQueryParameter("c"));
                      intent.putExtra("timestamp", code.getQueryParameter("t"));
                      setResult(Activity.RESULT_OK, intent);
                      finish();
                  }
                }
            }

            @Override
            public void qrCodeNotFound() {
             
            }
        }));
        Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector,imageAnalysis, preview);

    }
}

And my ActivityResultLauncher:

  ActivityResultLauncher<Intent> startQRActivity = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    // Add same code that you want to add in onActivityResult method
                    if (result.getResultCode() == Activity.RESULT_OK) {
                        // There are no request codes
                        Intent data = result.getData();
                       String code = data.getStringExtra("voucherCode");
                       String time = data.getStringExtra("timestamp");
                       voucherDetailBusinessDialog dia = new voucherDetailBusinessDialog(getColor(R.color.appThemeColor), getColor(R.color.orange), code);
                       dia.show(getSupportFragmentManager(),null);
                    }
                }
            });

Leave a Comment