Create Qr scanner for android using mobile vision api by google

Posted By : Keshav Gupta | 29-Jul-2018

Steps to Configure In android

Step1: Install google play services dependency in the application. Add dependency in app/build.gradle.

implementation 'com.google.android.gms:play-services:10.2.0'

Step2: Create a layout having component SurfaceView to open camera and toolbar showing the label for the scan and a view floating over the surface view that represents scan area to be scanned by this.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    >

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/bggradientdrawable">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <ImageView
                android:id="@+id/image_back_icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:padding="@dimen/margin_5"
                android:src="@drawable/back" />
            <TextView
                android:id="@+id/label_toolbar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toRightOf="@+id/image_back_icon"
                android:layout_centerVertical="true"
                android:fontFamily="@font/lato_regular"
                android:layout_marginLeft="@dimen/margin_10"
                android:text="@string/scan"
                android:textColor="@color/colorlogintop"
                android:textSize="@dimen/textsize_18sp" />


        </RelativeLayout>

    </android.support.v7.widget.Toolbar>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/code_info"
        android:layout_below="@+id/toolbar">

        <SurfaceView
            android:id="@+id/camera_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
        <RelativeLayout
            android:id="@+id/rl_qrlabel"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:visibility="gone"
            >
            <TextView
                android:id="@+id/text_scanlabel"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/scanatqr"
                android:fontFamily="@font/lato_regular"
                android:textColor="@color/colorlogintop"
                android:gravity="center"
                />

            <ImageView
                android:layout_width="@dimen/margin_200"
                android:layout_height="@dimen/margin_200"
                android:layout_below="@+id/text_scanlabel"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="16dp"
                android:src="@drawable/qrcode"
                android:id="@+id/imageView4" />
        </RelativeLayout>
    </FrameLayout>

    <TextView
        android:id="@+id/code_info"
        android:layout_width="match_parent"
        android:layout_height="@dimen/margin_40"
        android:visibility="gone"
        android:layout_alignParentBottom="true"
        android:text="" />
</RelativeLayout>

Step3:In AndroidManifest.xml file,create a metadata in <application> </application> tag showing  mobile vision dependencies for barcode.

 <meta-data
            android:name="com.google.android.gms.vision.DEPENDENCIES"
            android:value="barcode" />

Step4: Further add user permission for camera and Read_External_Storage under <Manifest> </Manifest> tag.Camera permission is required for accessing camera hardware and to customize camera on another view.

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
   <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CAMERA"/>

Note: For Android Version 6.0 and above you need to define user permission model for taking permission at runtime.?

Step5: Create an Activity class named as CameraPreviewScreen that will represent behavior action for SurfaceView and a CameraSource and BarcodeDetector.We will create BarcodeDetector object and set Barcode format to Qr as we are going to create Qr scanner and build it.

Step6: Next we will create CameraSource class object and set Camera attributes like as autofocus enabled to true, preview size and Camera source builder attribute to barcode detector.

Step7: Next we will set SurfaceView callback. In overridden methods onSurfaceCreated() camera source will start and onSurfaceDestroyed() camera source will be stopped.

Step8: Now we will set processor on the barcode detector. In overridden method, onReceiveDetections(), we will get scanned value and I am showing an AlertDialog showing scanned value and ok and cancel button. If you wanted to go with the scanned value. Press ok otherwise cancel to further rescan the Qr.

Step9: Code will be like

public class CameraPreviewScreen extends AppCompatActivity {

    @BindView(R.id.rl_qrlabel) RelativeLayout rLayout_QrcodeWindow;
    @BindView(R.id.image_back_icon) ImageView iv_backbtn;
    @BindView(R.id.camera_view) SurfaceView cameraView;
    @BindView(R.id.code_info) TextView barcodeInfo;
    @BindView(R.id.text_scanlabel) TextView tv_label_qr;
    @BindView(R.id.label_toolbar) TextView tv_toolbartext;
    private BarcodeDetector barcodeDetector;
    private CameraSource cameraSource;
    private AppCompatActivity activity;
    private AlertDialog dialog;
    private String scannedMesg;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.qrcamerascreen);
        getSupportActionBar().hide();
        ButterKnife.bind(this);
        activity=CameraPreviewScreen.this;
                showViewBarcode();
    }

  private void showViewBarcode()
  {

      if(barcodeDetector==null)
      {
          barcodeDetector =
                  new BarcodeDetector.Builder(this)
                          .setBarcodeFormats(Barcode.QR_CODE)
                          .build();
      }
      int dimenswidth=getResources().getDimensionPixelSize(R.dimen.margin_200);
      cameraSource = new CameraSource
              .Builder(this, barcodeDetector)
              .setAutoFocusEnabled(true).setRequestedPreviewSize(dimenswidth, dimenswidth)
              .build();


      cameraView.getHolder().addCallback(new SurfaceHolder.Callback() {
          @Override
          public void surfaceCreated(SurfaceHolder holder) {
              try {
                  cameraSource.start(cameraView.getHolder());
                  rLayout_QrcodeWindow.setVisibility(View.VISIBLE);
              } catch (IOException ie) {
                  Logger.LogError("CAMERA SOURCE", ie.getMessage());
              }catch (SecurityException ie) {
                  Logger.LogError("CAMERA SOURCE", ie.getMessage());
              }
          }

          @Override
          public void surfaceChanged(SurfaceHolder surfaceholder, int sformat, int swidth, int sheight) {

          }

          @Override
          public void surfaceDestroyed(SurfaceHolder holder) {
              cameraSource.stop();
              rLayout_QrcodeWindow.setVisibility(View.GONE);
          }
      });


      barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
          @Override
          public void release() {

          }

          @Override
          public void receiveDetections(Detector.Detections<Barcode> detections) {
              final SparseArray<Barcode> barcodes = detections.getDetectedItems();

              if (barcodes.size() != 0) {
                  barcodeInfo.post(new Runnable() {    // Use the post method of the TextView
                      public void run() {

                          Logger.LogError("Code",barcodes.valueAt(0).displayValue);

                          showMessageDialog(barcodes.valueAt(0).displayValue);
                          if(barcodeDetector!=null)
                          {
                              barcodeDetector.release();
                          }


                      }
                  });
              }
          }
      });
  }


    @OnClick(R.id.image_back_icon)
    public void onClickBack() {
        finish();
    }


    private void showMessageDialog(final String mesg)
    {

        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setTitle(R.string.QRCode);
        String s=mesg;
        if(s.contains(":")){
            s=s.substring(s.indexOf(":")+1);
        }
        if(s.contains("?")) {
            s=s.substring(0,s.indexOf("?"));
        }

        scannedMesg=s;
        builder.setMessage(s);
        builder.setCancelable(false);
        String positiveText = getString(android.R.string.ok);
        builder.setPositiveButton(positiveText,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                       dialog.dismiss();
                        // code to do when scanning is done properly
                           invokeSendCoinsWithWallet(scannedMesg);
                           finish();
                    }
                });
        String negativeText = getString(android.R.string.cancel);
        builder.setNegativeButton(negativeText,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        if(cameraSource!=null)
                        {
                            if(barcodeDetector !=null)
                            {
                                barcodeDetector.release();
                            }
                           // cameraSource.release();
                            cameraSource.stop();
                        }
                        Intent intent=new Intent(CameraPreviewScreen.this,CameraPreviewScreen.class);
                        startActivity(intent);
                        finish();

                    }
                });


        dialog = builder.create();
        // display dialog
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);
        if(!dialog.isShowing())
        {
            dialog.show();
        }
    }

    private void invokeSendCoinsWithWallet(String  walletAddress){
        Intent intent=new Intent();
        intent.setAction(IntentKeys.INTENT_KEY_QR_ACTION);
        intent.putExtra(IntentKeys.INTENT_KEY_QR_SCANNED,walletAddress);
        sendBroadcast(intent);
    }
}

That's all we have to do for QR scanning.

About Author

Author Image
Keshav Gupta

Keshav Gupta is Android Developer in Oodles, he always look forward for new tasks and new things to learn more.

Request for Proposal

Name is required

Comment is required

Sending message..