5

I have tried new Google Play Services feature - Barcode/QR scanner. In sample application is scanning started by taping on button and result is returned also on tap.

Is there a way to change its behavior to return first detected barcode/QR immediately?

I am not the first one curious about this.

Thank you in advance.

JerabekJakub
  • 5,268
  • 4
  • 26
  • 33

2 Answers2

15

I would advice against creating static variables. They will bite you later.
My recommendation is to create some kind of listener/callback on your TrackerFactory and use it on your Trackers. This is the pattern that Fragments, Adapters and plenty of other Android classes use, so why not copy them?

Step 1: Create an Interface in your BarcodeGraphicTracker (code for parts that changed): Here listener is initialised which sends the final callback response upon first successful detection, back to Tracker Activity (one where camera first opens).

public class BarcodeGraphicTracker extends Tracker<Barcode> {
    private GraphicOverlay<BarcodeGraphic> mOverlay;
    private BarcodeGraphic mGraphic;
    private NewDetectionListener mListener;

[...]
    @Override
    public void onNewItem(int id, Barcode item) {
        mGraphic.setId(id);
        if (mListener != null) mListener.onNewDetection(item);
    }

    public void setListener(NewDetectionListener mListener) {
        this.mListener = mListener;
    }
[...]
    public interface NewDetectionListener {
        void onNewDetection(Barcode barcode);
    }
}

Step 2: Change the Constructor of your BarcodeTrackerFactory to implement the interface. The listener instance is passed on to BarcodeGraphicTracker for initialisation. Code:

public class BarcodeTrackerFactory implements MultiProcessor.Factory<Barcode> {
private BarcodeGraphicTracker.NewDetectionListener newDetectionListener;
private GraphicOverlay<BarcodeGraphic> mGraphicOverlay;

public BarcodeTrackerFactory(GraphicOverlay<BarcodeGraphic> barcodeGraphicOverlay, BarcodeGraphicTracker.NewDetectionListener listener) {
    mGraphicOverlay = barcodeGraphicOverlay;
    newDetectionListener = listener;
}

@Override
public Tracker<Barcode> create(Barcode barcode) {
    BarcodeGraphic graphic = new BarcodeGraphic(mGraphicOverlay);
    BarcodeGraphicTracker tracker = new BarcodeGraphicTracker(mGraphicOverlay, graphic);
    if (newDetectionListener != null) tracker.setListener(newDetectionListener);
    return tracker;
}
}

Final Step: In your Tracker Activity initialise detector instance with the callback. This callback can be used to listen the data from first detected Bar/QR Code.

BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build();
BarcodeTrackerFactory barcodeFactory = new BarcodeTrackerFactory(graphicOverlay,
new BarcodeGraphicTracker.NewDetectionListener() {
    @Override
    public void onNewDetection(Barcode barcode) {
        Log.d("Barcode detected! - " + barcode.displayValue);

        //To send the result back to the Activity which is waiting for the result
        Intent data = new Intent();
        data.putExtra(BarcodeObject, barcode);
        setResult(CommonStatusCodes.SUCCESS, data);
        finish();
    }
 });
barcodeDetector.setProcessor(new MultiProcessor.Builder<>(barcodeFactory).build());
sud007
  • 5,824
  • 4
  • 56
  • 63
Tsuharesu
  • 1,090
  • 1
  • 13
  • 21
  • 1
    Works like a charm!! This way is better than accepted answer. – SadeghAlavizadeh Apr 24 '16 at 10:02
  • 1
    This post also utilizes a similar method (an activity callback) for those who want additional reference on the idea: http://stackoverflow.com/questions/32021193/how-to-capture-barcode-values-using-the-new-barcode-api-in-google-play-services?rq=1 I also agree that this method is better than creating a static reference to your activity. – Chris Jun 11 '16 at 13:58
  • Works great!! Thanks – user680891 Mar 29 '17 at 20:11
  • Correct and recommended style. Works like a charm! Thanks. Suggestion: Correctly order the 3 examples above, easier to implement for beginners. – sud007 Jul 31 '17 at 11:26
  • Appreciate it. Works perfectly. – Custadian Dec 19 '17 at 05:48
8

UPDATE!

For future readers you can use this project, which includes a full screen preview on almost all devices as well. The previous answer was not a solid implementation but more of a quick solution. The github repository contains all the changes and check the changelog as well.

  1. MainAcitivity.java
  2. BarcodeCaptureActivity.java
  3. CameraSource.java
  4. BarcodeGraphicTracker.java
wax911
  • 429
  • 3
  • 12
  • Thank you, I'll give it a try. – JerabekJakub Oct 31 '15 at 11:42
  • @JerabekJakub dont forget to upvote good answers. (specially meaningful if the individual has few rep points) – Jeremie D Nov 18 '15 at 19:37
  • 1
    Don't worry guys, I have this page still opened in my browser, just don't have enought time to try it. :-( I'll do it asap. – JerabekJakub Nov 20 '15 at 12:09
  • It works, I've done it and am using it.. (and added relevant code in case you need to know how to startActivityForResult and get the relevant result.) – Jeremie D Nov 20 '15 at 17:49
  • Tested and works! Thank you very much. Answer is upvoted and approved now! – JerabekJakub Nov 24 '15 at 08:34
  • what is ActivitySource? – rookieDeveloper Sep 02 '16 at 15:13
  • @gaurav A class, that approach is way out of date and also wasn't the best of implementations. You might want to check out the my repository here same as that given above [Github Project](https://github.com/wax911/Vision-Barcode-Scanner) – wax911 Sep 24 '16 at 17:07
  • A class that only contains a static reference of an activity used as an interface. And then logging info/debug stuff as error. This code belongs to the 7th circle of hell – Chisko Nov 21 '17 at 04:51