Nowadays Barcodes and QR Codes are widely used in lot of mobile apps. In a QR Code you can store information like text, sms, email, url, image, audio and few other formats. In Android you can extract the information stored in barcodes by using Google Vision Library. Even though there are lot of other libraries available, google vision library is best to consider as it’s not only provide barcode reading but also have other features like face detection, text detection.

In this article we are going to learn how to use the google vision library by creating a simple movie ticket scanning app.

android-barcode-reader-google-vision

1. Google Mobile Vision API

Google Mobile Vision api helps in finding objects in an image or video. It provides functionalities like face detection, text detection and barcode detection. All these functionalities can be used separately or combined together.

This article aims to explain the barcode detection with a realtime use case scenario. We can see lot of barcode scanning apps used in supermarkets, theatres and hotels which scans a barcode and provides user desired information. In this article we’ll try to build a simple movie ticket scanner app which scans a barcode / qrcode and displays the movie information to book a ticket.

The google vision library is a part of play services and can be added to your project’s build.gradle.

compile 'com.google.android.gms:play-services-vision:11.0.2'

2. Barcode Scanner Library

Google provided a simple tutorial to tryout the barcode scanning library with a simple bitmap image. But when it comes to scanning a realtime camera feed for a barcode, things become difficult to implement as we need to perform barcode detection on camera video.

I have developed a simple barcode scanner library by forking the google vision sample. In this library few bugs were fixed and added other functionalities like callbacks when barcode is scanned and a overlay scanning line indicator that can be used in your apps.

3. How to Use the Barcode library

Follow the below simple steps to include the barcode / qrcode library in your project.

1. Add the androidhive barcode reader and google vision library to your app’s build.gradle file.

This article was written using Android Studio 3.0 Canary 9. The command compile is deprecated and replaced with implementation

dependencies {
    // barcode reader library
    implementation 'info.androidhive:barcode-reader:1.1.5'

    // google vision library
    implementation 'com.google.android.gms:play-services-vision:11.0.2'
}

2. Add the barcode camera fragment to your activity or fragment.

<fragment
        android:id="@+id/barcode_scanner"
        android:name="info.androidhive.barcode.BarcodeReader"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:auto_focus="true"
        app:use_flash="false" />

3. Implement your Activity from BarcodeReader.BarcodeReaderListener and override the necessary methods.

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.SparseArray;
import com.google.android.gms.vision.barcode.Barcode;
import java.util.List;

import info.androidhive.barcode.BarcodeReader;

public class MainActivity extends AppCompatActivity implements BarcodeReader.BarcodeReaderListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scan);
    }

    @Override
    public void onScanned(Barcode barcode) {
        // single barcode scanned
    }

    @Override
    public void onScannedMultiple(List<Barcode> list) {
        // multiple barcodes scanned
    }

    @Override
    public void onBitmapScanned(SparseArray<Barcode> sparseArray) {
        // barcode scanned from bitmap image
    }

    @Override
    public void onScanError(String s) {
        // scan error
    }

    @Override
    public void onCameraPermissionDenied() {
        // camera permission denied
    }
}

4. Run your project and try to scan barcode or qrcode. The scanned result will be returned in onScanned() or onScannedMultiple() method.

3.1 Adding Scanning Overlay Indicator Line

We can see all the scanning apps generally adds an indicator line on the camera overlay to indicate the scanning progress in going on. To achieve this, I have added a reusable class in the same library which can be added on to camera screen.

To add the animating scanning line, add the info.androidhive.barcode.ScannerOverlay to same activity overlapping the camera fragment.

<info.androidhive.barcode.ScannerOverlay
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#44000000"
    app:line_color="#7323DC"
    app:line_speed="6"
    app:line_width="4"
    app:square_height="200"
    app:square_width="200"/>

The library also contains few other useful functionalities like auto flash, beep sound etc., Detailed information about library can be found on it’s Github page.

4. Creating New Project – Building Simple Ticket Scanning App

As the barcode scanning library is already available, we’ll see how to use the library considering a real use case scenario. The app we are going to build not only explains the barcode scanning, but it also covers building the complex UI, making REST api calls to fetch the movie json and writing custom view classes.

Overall the app contains three screens. The first is splash screen, second is barcode scanning and the last one is to display the movie ticket information.

Below are the screenshots of the app.

android-barcode-reader-google-vision

4.1 The REST API

To build this app we need a REST api to search through movie database by movie barcode. I have written a simple rest api to search for a movie by barcode. This takes predefined barcode value as query param and searches it in the db. Here are the few sample barcodes for testing.

1. dn_barcode.jpg
2. spiderman_barcode.jpg
3. wonderwoman_barcode.jpg
4. dunkirk_barcode.jpg

Search Movie:
Make GET request with the barcode value read.
https://api.androidhive.info/barcodes/search.php?code=dunkirk

Movie Result:
The matched movie json will be given in the response.

{
	"name": "Dunkirk",
	"poster": "https://api.androidhive.info/barcodes/dunkirk.jpg",
	"duration": "1hr 46min",
	"rating": 4.6,
	"released": true,
	"genre": "Action",
	"price": "₹200",
	"director": "Christopher Nolan"
}

Now we have all the necessary information with us. Let’s start by creating a new project in Android Studio.

Note: This project is developed using Android Studio 3.0 Canary 9

1. Create a new project in Android Studio from File ⇒ New Project and fill the project details. I gave project name as MovieTickets and package name as info.androidhive.movietickets

2. Open app’s build.gradle and add the barcode and google vision dependencies. I am also adding Glide, Volley and Gson libraries as they are required to make http calls, json parsing and display images.

dependencies {
    implementation 'com.google.android.gms:play-services-vision:11.0.2'

    // vision barcode scanner
    implementation 'info.androidhive:barcode-reader:1.1.2'

    // glide image library
    implementation 'com.github.bumptech.glide:glide:4.0.0-RC1'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0-RC1'

    implementation 'com.android.volley:volley:1.0.0'
    implementation 'com.google.code.gson:gson:2.6.2'
}

3. Add the below string, dimen, color resources to respective files under res directory.

<resources>
    <string name="app_name">Movie Tickets</string>
    <string name="title_activity_ticket">Book Ticket</string>
    <string name="lbl_duration">DURATION</string>
    <string name="lbl_genre">GENRE</string>
    <string name="lbl_rating">RATING</string>
    <string name="lbl_price">PRICE</string>
    <string name="btn_buy_now">BUY NOW</string>
    <string name="btn_coming_soon">COMING SOON</string>
    <string name="msg_no_ticket_found">No ticket found. Try scanning the QR Codes from http://api.androidhive.info/qrcodes/</string>
</resources>

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="dimen_20">20dp</dimen>
    <dimen name="dimen_10">10dp</dimen>
    <dimen name="activity_margin">16dp</dimen>
    <dimen name="lbl_directory">14dp</dimen>
    <dimen name="lbl_movie_name">28dp</dimen>
    <dimen name="img_poster_height">220dp</dimen>
    <dimen name="dimen_40">40dp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#6d0094</color>
    <color name="colorPrimaryDark">#6d0094</color>
    <color name="colorAccent">#ff2068</color>
    <color name="colorAccentSecondary">#ad1a7f</color>
    <color name="viewBg">#f8f8f8</color>
    <color name="btn_disabled">#999</color>
    <color name="lbl_value">#222222</color>
</resources>

4. Create a class named MyApplication.java and add the below code. Here we create volley singleton instance.

Volley is not suggested for making http calls, but to make the integration simple, it’s considered in this tutorial. Consider using Retrofit in your production apps.

import android.app.Application;
import android.text.TextUtils;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;

/**
 * Created by ravi on 31/07/17.
 */

public class MyApplication extends Application {

    public static final String TAG = MyApplication.class
            .getSimpleName();

    private RequestQueue mRequestQueue;

    private static MyApplication mInstance;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized MyApplication getInstance() {
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }

        return mRequestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req, String tag) {
        // set the default tag if tag is empty
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }

    public <T> void addToRequestQueue(Request<T> req) {
        req.setTag(TAG);
        getRequestQueue().add(req);
    }

    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

5. Open AndroidManifest.xml and add the MyApplication class to <applicaton> tag. Also add the INTERNET permission as we need to make http calls.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.movietickets">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".ScanActivity"
            android:screenOrientation="portrait" />
        <activity
            android:name=".TicketActivity"
            android:label="@string/title_activity_ticket"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme.NoActionBar"></activity>
    </application>
</manifest>

6. Under res ⇒ drawable folder create an xml drawable named bg_gradient.xml This drawable gives gradient background to view.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient
        android:angle="135"
        android:centerColor="@color/colorAccentSecondary"
        android:endColor="@color/colorPrimary"
        android:startColor="@color/colorAccent"
        android:type="linear" />

    <corners android:radius="0dp" />
</shape>

4.2 Adding Landing Screen

The landing screen will have few text fields and a button to open the scanner camera. The interesting thing you will learn here is giving gradient background to activity.

7. Open the layout file your main activity (activity_main.xml) add the below layout. Here we are adding button to launch scanner activity.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg_gradient"
    tools:context="info.androidhive.movietickets.MainActivity">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:orientation="vertical"
        android:paddingLeft="40dp"
        android:paddingRight="40dp">

        <ImageView
            android:id="@+id/icon"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_centerHorizontal="true"
            android:clickable="true"
            android:foreground="?attr/selectableItemBackground"
            android:src="@drawable/qrcode"
            android:tint="@android:color/white" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"
            android:fontFamily="sans-serif-light"
            android:gravity="center"
            android:text="Scan the QR code on the poster and book your movie tickets"
            android:textColor="@android:color/white"
            android:textSize="16dp" />
    </LinearLayout>

    <Button
        android:id="@+id/btn_scan"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="40dp"
        android:background="@android:color/transparent"
        android:foreground="?attr/selectableItemBackground"
        android:paddingLeft="20dp"
        android:paddingRight="20dp"
        android:fontFamily="sans-serif-medium"
        android:text="Scan QR Code"
        android:textColor="@android:color/white"
        android:textSize="18sp" />

</RelativeLayout>

8. Open the main activity and do the below necessary changes. In this activity transparentToolbar() method makes toolbar transparent. The button click listener launches the scanner activity which we are going to create shortly.

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.SparseArray;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

import com.google.android.gms.vision.barcode.Barcode;

import java.util.List;

import info.androidhive.barcode.BarcodeReader;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // making toolbar transparent
        transparentToolbar();

        setContentView(R.layout.activity_main);

        findViewById(R.id.btn_scan).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(MainActivity.this, ScanActivity.class));
            }
        });
    }

    private void transparentToolbar() {
        if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
            setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, true);
        }
        if (Build.VERSION.SDK_INT >= 19) {
            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
        }
        if (Build.VERSION.SDK_INT >= 21) {
            setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }
    }

    private void setWindowFlag(Activity activity, final int bits, boolean on) {
        Window win = activity.getWindow();
        WindowManager.LayoutParams winParams = win.getAttributes();
        if (on) {
            winParams.flags |= bits;
        } else {
            winParams.flags &= ~bits;
        }
        win.setAttributes(winParams);
    }
}

If you run the app, you can see the landing screen as below.

4.3 Adding Ticket Scan Screen

Now we have the landing screen ready. Let’s create the scanner activity.

9. Create a new activity from File ⇒ New ⇒ Activity ⇒ Empty Activity and name it as ScanActivity.java

10. Open layout file of ticket activity (activity_scan.xml) and add the Barcode Reader fragment as below. Here we are also adding the scanner line indicator animation view.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="info.androidhive.movietickets.ScanActivity">

    <fragment
        android:id="@+id/barcode_scanner"
        android:name="info.androidhive.barcode.BarcodeReader"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:auto_focus="true"
        app:use_flash="false" />

    <info.androidhive.barcode.ScannerOverlay
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#44000000"
        app:line_color="#7323DC"
        app:line_speed="6"
        app:line_width="4"
        app:square_height="200"
        app:square_width="200" />

</RelativeLayout>

11. Open ScanActivity.java and do the below necessary changes.

> Implement the activity from BarcodeReader.BarcodeReaderListener
> Override the callback methods onScanned(), onScannedMultiple() and other callbacks.
> barcodeReader.playBeep() plays beep sound upon barcode is read.
> Launch the TicketActivity once the barcode is scanned by passing the barcode value in intent.

package info.androidhive.movietickets;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.SparseArray;
import android.widget.Toast;

import com.google.android.gms.vision.barcode.Barcode;

import java.util.List;

import info.androidhive.barcode.BarcodeReader;

public class ScanActivity extends AppCompatActivity implements BarcodeReader.BarcodeReaderListener {

    BarcodeReader barcodeReader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scan);

        // get the barcode reader instance
        barcodeReader = (BarcodeReader) getSupportFragmentManager().findFragmentById(R.id.barcode_scanner);
    }

    @Override
    public void onScanned(Barcode barcode) {

        // playing barcode reader beep sound
        barcodeReader.playBeep();

        // ticket details activity by passing barcode
        Intent intent = new Intent(ScanActivity.this, TicketActivity.class);
        intent.putExtra("code", barcode.displayValue);
        startActivity(intent);
    }

    @Override
    public void onScannedMultiple(List<Barcode> list) {

    }

    @Override
    public void onBitmapScanned(SparseArray<Barcode> sparseArray) {

    }

    @Override
    public void onCameraPermissionDenied() {
        finish();
    }

    @Override
    public void onScanError(String s) {
        Toast.makeText(getApplicationContext(), "Error occurred while scanning " + s, Toast.LENGTH_SHORT).show();
    }
}

Run the app and try to scan any barcode. The scanned barcode will be returned in onScanned() method.

4.4 Adding Ticket Scan Result Screen

The next screen will be ticket results activity. On this screen the movie details will be displayed by sending the scanned qrcode to search endpoint and get the result.

If you observe the design, I have placed the movie details on a ticket view which will have punched holes in the corners. To achieve this I have created a custom view and made the holes using eraser.

4.4.1 Preparing Ticket View with Punching Holes

12. Create a class named TicketView.java. This is a plain view class in which the Canvas is used to render the view with transparent holes on the corners.

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.widget.LinearLayout;

/**
 * Created by ravi tamada on 29/07/17.
 * Ticket view creates view with view punches making circular holes
 * in the view
 */

public class TicketView extends LinearLayout {
    private Bitmap bm;
    private Canvas cv;
    private Paint eraser;
    private int holesBottomMargin = 70;
    private int holeRadius = 40;

    public TicketView(Context context) {
        super(context);
        Init();
    }

    public TicketView(Context context, AttributeSet attrs) {
        super(context, attrs);
        Init();
    }

    public TicketView(Context context, AttributeSet attrs,
                      int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        Init();
    }

    private void Init() {
        eraser = new Paint();
        eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        eraser.setAntiAlias(true);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (w != oldw || h != oldh) {
            bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            cv = new Canvas(bm);
        }
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int w = getWidth();
        int h = getHeight();

        bm.eraseColor(Color.TRANSPARENT);

        // set the view background color
        cv.drawColor(Color.WHITE);

        // drawing footer square contains the buy now button
        Paint paint = new Paint();
        paint.setARGB(255, 250, 250, 250);
        paint.setStrokeWidth(0);
        paint.setStyle(Paint.Style.FILL);
        cv.drawRect(0, h, w, h - pxFromDp(getContext(), holesBottomMargin), paint);

        // adding punching holes on the ticket by erasing them
        cv.drawCircle(0, 0, holeRadius, eraser); // top-left hole
        cv.drawCircle(w / 2, 0, holeRadius, eraser); // top-middle hole
        cv.drawCircle(w, 0, holeRadius, eraser); // top-right
        cv.drawCircle(0, h - pxFromDp(getContext(), holesBottomMargin), holeRadius, eraser); // bottom-left hole
        cv.drawCircle(w, h - pxFromDp(getContext(), holesBottomMargin), holeRadius, eraser); // bottom right hole

        // drawing the image
        canvas.drawBitmap(bm, 0, 0, null);


        // drawing dashed lines at the bottom
        Path mPath = new Path();
        mPath.moveTo(holeRadius, h - pxFromDp(getContext(), holesBottomMargin));
        mPath.quadTo(w - holeRadius, h - pxFromDp(getContext(), holesBottomMargin), w - holeRadius, h - pxFromDp(getContext(), holesBottomMargin));

        // dashed line
        Paint dashed = new Paint();
        dashed.setARGB(255, 200, 200, 200);
        dashed.setStyle(Paint.Style.STROKE);
        dashed.setStrokeWidth(2);
        dashed.setPathEffect(new DashPathEffect(new float[]{10, 5}, 0));
        canvas.drawPath(mPath, dashed);

        super.onDraw(canvas);
    }

    public static float pxFromDp(final Context context, final float dp) {
        return dp * context.getResources().getDisplayMetrics().density;
    }
}

13. Create new class named TicketResultActivity.java by navigating to File ⇒ New ⇒ Activity ⇒ Empty Activity.

14. Open the layout of ticket result activity (activity_ticket_result.xml) and add the below layout.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg_gradient"
    android:descendantFocusability="beforeDescendants"
    android:fitsSystemWindows="true"
    tools:context=".TicketResultActivity">

    <android.support.design.widget.AppBarLayout
        foreground="?android:windowContentOverlay"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">


        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:background="@color/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay"></android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_ticket_details"/>

</android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg_gradient"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".TicketResultActivity">

    <TextView
        android:id="@+id/txt_error"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal"
        android:text="@string/msg_no_ticket_found"
        android:textColor="@android:color/white"
        android:padding="@dimen/dimen_20"
        android:textSize="16dp"
        android:visibility="gone" />

    <info.androidhive.movietickets.TicketView
        android:id="@+id/layout_ticket"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="@dimen/dimen_20"
        android:layout_marginRight="@dimen/dimen_20"
        android:layout_marginTop="@dimen/dimen_20"
        android:background="@android:color/transparent"
        android:orientation="vertical"
        android:paddingTop="@dimen/dimen_10"
        android:visibility="gone">

        <TextView
            android:id="@+id/director"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dp"
            android:fontFamily="sans-serif-condensed"
            android:paddingLeft="@dimen/activity_margin"
            android:paddingRight="@dimen/activity_margin"
            android:paddingTop="@dimen/activity_margin"
            android:textAllCaps="true"
            android:textSize="@dimen/lbl_directory" />

        <TextView
            android:id="@+id/name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fontFamily="sans-serif-condensed"
            android:paddingLeft="16dp"
            android:paddingRight="16dp"
            android:textAllCaps="true"
            android:textColor="#111"
            android:maxLines="1"
            android:ellipsize="end"
            android:textSize="@dimen/lbl_movie_name" />

        <ImageView
            android:id="@+id/poster"
            android:layout_width="match_parent"
            android:layout_height="@dimen/img_poster_height"
            android:layout_marginBottom="@dimen/activity_margin"
            android:layout_marginTop="@dimen/activity_margin"
            android:scaleType="centerCrop" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:paddingLeft="@dimen/activity_margin"
            android:paddingRight="@dimen/activity_margin"
            android:weightSum="2">

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="5dp"
                    android:fontFamily="sans-serif-condensed"
                    android:text="@string/lbl_duration"
                    android:textSize="12dp" />

                <TextView
                    android:id="@+id/duration"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:fontFamily="sans-serif-condensed"
                    android:textColor="@color/lbl_value"
                    android:textSize="22dp" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="5dp"
                    android:fontFamily="sans-serif-condensed"
                    android:text="@string/lbl_genre"
                    android:textSize="12dp" />

                <TextView
                    android:id="@+id/genre"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:fontFamily="sans-serif-condensed"
                    android:textAllCaps="true"
                    android:textColor="@color/lbl_value"
                    android:textSize="22dp" />
            </LinearLayout>

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:orientation="horizontal"
            android:paddingLeft="16dp"
            android:paddingRight="16dp"
            android:weightSum="2">

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="5dp"
                    android:fontFamily="sans-serif-condensed"
                    android:text="@string/lbl_rating"
                    android:textSize="12dp" />

                <TextView
                    android:id="@+id/rating"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:fontFamily="sans-serif-condensed"
                    android:textColor="@color/lbl_value"
                    android:textSize="22dp" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="5dp"
                    android:fontFamily="sans-serif-condensed"
                    android:text="@string/lbl_price"
                    android:textSize="12dp" />

                <TextView
                    android:id="@+id/price"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:fontFamily="sans-serif-condensed"
                    android:textAllCaps="true"
                    android:textColor="@color/lbl_value"
                    android:textSize="22dp" />
            </LinearLayout>

        </LinearLayout>

    </info.androidhive.movietickets.TicketView>

    <Button
        android:id="@+id/btn_buy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="10dp"
        android:background="@android:color/transparent"
        android:fontFamily="sans-serif-condensed"
        android:foreground="?attr/selectableItemBackground"
        android:paddingLeft="@dimen/activity_margin"
        android:paddingRight="@dimen/activity_margin"
        android:textColor="@color/colorPrimary"
        android:textSize="26dp" />

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="@dimen/dimen_40"
        android:layout_height="@dimen/dimen_40"
        android:layout_centerInParent="true"
        android:indeterminateTint="@android:color/white"
        android:indeterminateTintMode="src_atop"
        android:visibility="visible" />
</RelativeLayout>

15. Open the respective TicketResultActivity.java and modify the code as below.

> searchBarcode() makes the volley http call to search endpoint by passing the barcode scanned.
> renderMovie() parses the json and renders the movie details on the screen.

import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.bumptech.glide.Glide;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.annotations.SerializedName;

import org.json.JSONObject;

public class TicketResultActivity extends AppCompatActivity {
    private static final String TAG = TicketResultActivity.class.getSimpleName();

    // url to search barcode
    private static final String URL = "https://api.androidhive.info/barcodes/search.php?code=";

    private TextView txtName, txtDuration, txtDirector, txtGenre, txtRating, txtPrice, txtError;
    private ImageView imgPoster;
    private Button btnBuy;
    private ProgressBar progressBar;
    private TicketView ticketView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ticket_result);

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        txtName = findViewById(R.id.name);
        txtDirector = findViewById(R.id.director);
        txtDuration = findViewById(R.id.duration);
        txtPrice = findViewById(R.id.price);
        txtRating = findViewById(R.id.rating);
        imgPoster = findViewById(R.id.poster);
        txtGenre = findViewById(R.id.genre);
        btnBuy = findViewById(R.id.btn_buy);
        imgPoster = findViewById(R.id.poster);
        txtError = findViewById(R.id.txt_error);
        ticketView = findViewById(R.id.layout_ticket);
        progressBar = findViewById(R.id.progressBar);

        String barcode = getIntent().getStringExtra("code");

        // close the activity in case of empty barcode
        if (TextUtils.isEmpty(barcode)) {
            Toast.makeText(getApplicationContext(), "Barcode is empty!", Toast.LENGTH_LONG).show();
            finish();
        }

        // search the barcode
        searchBarcode(barcode);
    }

    /**
     * Searches the barcode by making http call
     * Request was made using Volley network library but the library is
     * not suggested in production, consider using Retrofit
     */
    private void searchBarcode(String barcode) {
        // making volley's json request
        JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
                URL + barcode, null,
                new Response.Listener<JSONObject>() {

                    @Override
                    public void onResponse(JSONObject response) {
                        Log.e(TAG, "Ticket response: " + response.toString());

                        // check for success status
                        if (!response.has("error")) {
                            // received movie response
                            renderMovie(response);
                        } else {
                            // no movie found
                            showNoTicket();
                        }
                    }
                }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(TAG, "Error: " + error.getMessage());
                showNoTicket();
            }
        });

        MyApplication.getInstance().addToRequestQueue(jsonObjReq);
    }

    private void showNoTicket() {
        txtError.setVisibility(View.VISIBLE);
        ticketView.setVisibility(View.GONE);
        progressBar.setVisibility(View.GONE);
    }

    /**
     * Rendering movie details on the ticket
     */
    private void renderMovie(JSONObject response) {
        try {

            // converting json to movie object
            Movie movie = new Gson().fromJson(response.toString(), Movie.class);

            if (movie != null) {
                txtName.setText(movie.getName());
                txtDirector.setText(movie.getDirector());
                txtDuration.setText(movie.getDuration());
                txtGenre.setText(movie.getGenre());
                txtRating.setText("" + movie.getRating());
                txtPrice.setText(movie.getPrice());
                Glide.with(this).load(movie.getPoster()).into(imgPoster);

                if (movie.isReleased()) {
                    btnBuy.setText(getString(R.string.btn_buy_now));
                    btnBuy.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
                } else {
                    btnBuy.setText(getString(R.string.btn_coming_soon));
                    btnBuy.setTextColor(ContextCompat.getColor(this, R.color.btn_disabled));
                }
                ticketView.setVisibility(View.VISIBLE);
                progressBar.setVisibility(View.GONE);
            } else {
                // movie not found
                showNoTicket();
            }
        } catch (JsonSyntaxException e) {
            Log.e(TAG, "JSON Exception: " + e.getMessage());
            showNoTicket();
            Toast.makeText(getApplicationContext(), "Error occurred. Check your LogCat for full report", Toast.LENGTH_SHORT).show();
        } catch (Exception e) {
            // exception
            showNoTicket();
            Toast.makeText(getApplicationContext(), "Error occurred. Check your LogCat for full report", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            finish();
        }
        return super.onOptionsItemSelected(item);
    }

    private class Movie {
        String name;
        String director;
        String poster;
        String duration;
        String genre;
        String price;
        float rating;

        @SerializedName("released")
        boolean isReleased;

        public String getName() {
            return name;
        }

        public String getDirector() {
            return director;
        }

        public String getPoster() {
            return poster;
        }

        public String getDuration() {
            return duration;
        }

        public String getGenre() {
            return genre;
        }

        public String getPrice() {
            return price;
        }

        public float getRating() {
            return rating;
        }

        public boolean isReleased() {
            return isReleased;
        }
    }
}

Now if you run the app and scan the qr codes provided in this article, the results will be shown as below.

5. Testing the App

The app can scan any barcode but the movie ticket information will be shown only when the qr code is scanned provided in this article.

Run the app and try to scan the below qr codes. You should able to see the proper movie information as shown in the demo.

1. dn_barcode.jpg
2. spiderman_barcode.jpg
3. wonderwoman_barcode.jpg
4. dunkirk_barcode.jpg

Hi there! I am Founder at androidhive and programming enthusiast. My skills includes Android, iOS, PHP, Ruby on Rails and lot more. If you have any idea that you would want me to develop? Let’s talk: ravi@androidhive.info
  • Thank you so much for another great tutorial! You are a specialist!

    • You are welcome 🙂

      • sardar khan

        Hy @ravi8x:disqus Thanks for the tutorial how to solve this issue..
        Gradle sync failed: Could not find method implementation() for arguments [info.androidhive:barcode-reader:1.1.2] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.

        • You have to use latest Android Studio (3.0)
          https://developer.android.com/studio/preview/index.html

          • sardar khan

            Currently iam not using android studio 3.0 can i use this tutorial..? or you can refer another tutorial for this..?

          • The barcode library works with any Android Studio version. If you want to try this tutorial in Android Studio 2.x, replace implementation to compile in your gradle file. You might face other errors too but can be solved easily.

  • Sagar Chavda

    It’s really very nice tutorial with your own Barcode reader library. Great!

  • Muhammad Alvin Ramadhan

    Great tutorial and awesome custom ticket views 🙂

    • Yup! cool part is Ticket View 😀

      • Muhammad Alvin Ramadhan

        it looks like your tutorial is mostly good, Can u make a tutorial about “Cab Selection (Navigation) like Uber in android please??”

  • tigani

    great……Firebase is blocked in my country im working on a project that iwant to send notification when new data inserted to mysql …could you please guide me….im sorry my question not belong to the topic above ..thanks in advance.

  • Virender Dall

    Your tutorial always helps me 🙂

    I am waiting for a tutorial on fragment navigation with animation.

    • Any example of the animations you are looking for?

  • Amar Ilindra

    Why Volley is not recommended?

    • It’s not actively developed and it’s lack of lot of features. Volley is better smaller network responses. Retrofit has more benefits than volley.

  • OTONG

    how to make it offline apps :/ ?

    • Barcode can be detected offline, but in order to fetch data of barcode you need server. A simple text can be stored in barcode if that fulfils your app requirements .

  • CuriousPost

    Can you launch a tutorial on creating a news app with cards layout or something similar to Google news. Looking for the Article from long time.

  • akin

    Please am having error in activity_scan.xml

    Error:(9) No resource identifier found for attribute ‘auto_focus’ in package ‘

    Error:(9) No resource identifier found for attribute ‘use_flash’ in package ‘

    Error:(17) No resource identifier found for attribute ‘line_color’ in package

    Error:(17) No resource identifier found for attribute ‘line_speed’ in package

    Error:(17) No resource identifier found for attribute ‘line_width’ in package

    Error:(17) No resource identifier found for attribute ‘square_height’ in package

    Error:(17) No resource identifier found for attribute ‘square_width’ in package

    • Paste your complete xml code.

      • akin

        I got it done , I was the one making wrong imports

    • Narasimhareddy Meka

      i have also same issue create .plz solve my problem bro

  • Dev Mohanty

    Hi Ravi – Thanks for the great tut.
    Also what does the data endpoint look like? The php/api and the MySQL bit.

  • Raja

    How to create icon pack for android., pls help me

  • Oluflourish Emmanuel

    Wow…. Thanks for this great tutorial. You are the best…
    Please I’m having a problem. The app is not reading the barcodes. It just keeps scanning. Same thing happened when I downloaded the .apk file.
    I’m using Android Studio 2.3.3

  • Ramesh kumar

    As usual Ravi Tamada. very gud tutorial again….experting tutorial on Rxjava from you.

  • MD Danish Ansari

    Can you please do fb, twitter and g+ integration tutorial ?

    • No, consider using Firebase Federal Login.

  • Narasimhareddy Meka
    • I hope it has to be info.androidhive.barcode.ScannerOverlay instead of your com.example.dell.movieticket.ScanActivity.

      • sumit kumar

        then how to solve this problem plz help me.

  • Narasimhareddy Meka

    Solve my problem

  • bazilbuzz

    how to add custom url to buy now button?

  • Oussama EL AHMAR

    Thank you Mr Ravi, I always check your website for new things, it is always helpfull and good explained
    big thanks from Morocco country

  • tasa

    same. please check this ravi

    • RJ Meman

      Provide complete full screen for qr scan also hide above status bar that working for me

  • Brieda Abdulghafoor Muzembo

    Thanks the light you use to give us about android

    i’m getting some error
    1st Failed to resolve: annotations
    2nd

    • Have you added the androidhive barcode library in gradle file?

      • Brieda Abdulghafoor Muzembo

        yes sir

        • Try cleaning & building the project from Build menu option in Android Studio.

          • Brieda Abdulghafoor Muzembo

            i did but i’m still getting an the same error and also
            import info.androidhive.barcode.BarcodeReader
            gives error especially “BarcodeReader”
            i’m using android studio 3.0.0 beta 6

  • Rakshith Vikramraj

    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.thedreamlight.huntqr/com.thedreamlight.huntqr.ScanActivity}: android.view.InflateException: Binary XML file line #0: Binary XML file line #0: Class is not a View info.androidhive.barcode.BarcodeReader

    I GET THIS ERROR WHAT TO DO

    • Have you added androidhive barcode reader dependency in build.gradle?

    • Abhi

      Same error persist even after the changes done

      java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.abhi.scol/com.example.abhi.scol.TicketResultActivity}: android.view.InflateException: Binary XML file line #29: Binary XML file line #24: Error inflating class info.androidhive.movietickets.TicketView

      Caused by: java.lang.ClassNotFoundException: Didn’t find class “info.androidhive.movietickets.TicketView” on path: DexPathList

  • RJ Meman

    How to flash on/off programatically?

  • jithin

    this is the error that appears. i downloaded the code from the site itself. tried installing the missing repository and all but the same error keeps repeating . please tell me how to fix it. im a beginner to android. https://uploads.disquscdn.com/images/610e998787663e0b3dc21f9d348ef931c0af204a92039d2f18adb4d50a78f073.png

  • Ramij Meman

    camera result is not good when use this code inside Fragment.

    • Bhaskar

      Me too have same issue. The camera is not showing full screen in fragment.

  • Dharm

    It is taking around 1.5 sec to intent from ScanActivity to TicketResultActivity. So is there any way we can optimize and reduce time.

  • Zar Ni

    Very Nice Tutorial. Thanks !!

  • Festus Tamakloe

    Great Tuto. Please could you also post the PHP code here?

    • There is no logic involved php. It just prints the json file by file name.

      • Dammah SifLa

        I have message ‘barcode is empty’…
        Whats problem ??
        Pleasss share konsep php code…
        Thanks…

  • Abhi

    Error in log
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.abhi.scol/com.example.abhi.scol.TicketResultActivity}: android.view.InflateException: Binary XML file line #29: Binary XML file line #24: Error inflating class info.androidhive.movietickets.TicketView

    Caused by: java.lang.ClassNotFoundException: Didn’t find class “info.androidhive.movietickets.TicketView” on path: DexPathList

    Unable to scan

    • Vasudha Bonde

      hey, did you solve this exception because i have giving same exception. please let me know if you solve.

      • Have you added the androidhive barcode library to gradle?

        • Vasudha Bonde

          yes i added barcode library. In my application i used bottom navigation view so that i added scanner in fragment that’s why its giving android.view.InflateException: Binary XML file line #0: Error inflating class fragment exception. but i couldn’t find any solution.

          • Can you post your layout code?

          • Vasudha Bonde

            my xml layout

          • Seems the below code is wrong. It won’t take use_flash or auto_focus properties. Try removing unnecessary attributes.

      • Abhi

        Try it in a different Package it is working for me.

  • Abhi

    same for micromax A1

  • mahmoud saad

    samsung mobiles android version 4 can’t scan QR code , do you have any solution for that ?

    • Is there any error report to debug?

      • mahmoud saad

        it gives error D/Camera: app passed NULL surface and device can’t support auto scan

  • Viloria Anaya Vicky

    te felicito eres genial.
    podrias ayudarme con el archivo search.php, es que soy nuevo en esto

  • Vasudha Bonde

    i give android.view.InflateException: Binary XML file line #0: Error inflating class fragment exception in fragment. how to add BarcodeReader in fragment.

  • Sakhaa Awamleh

    How can I download your barcode reader library ?

  • Sakhaa Awamleh
  • Web light

    scanning lib codes please

  • Sampreet Singh

    Hi
    I have added this library in a view pager. I am facing an issue with barcode view in which camera view get starched. Please suggest me a solution.

  • Prathibha Nandini

    Mr. Tamada,

    How can we resist the fragment from stretching the camera. Images are stretched while scanning. I’ve posted images in git repo issue.

    Could you check that once, if possible.

  • Cahaya Alam

    https://uploads.disquscdn.com/images/608e664b1cdd9dba161a3ad1f0a5f6be750db20816b756b3f8a57ab47374428a.jpg Hi Ravi Tamada,
    Nice work, and thank you for tutorial and share code. Btw, when camera open to scan barcode, some display is green, how to fix it and make itu full screen.
    thanks before.

    • Which device you are testing it on?

    • Eric Zile Kouassi

      Hello Ravi,
      Sorry I’ve the same problem

      • Which device / os version you are testing it on?

        • Eric Zile Kouassi

          I’ve Samsung Galaxy J7 / Android 6.0

    • Ramij Meman

      I have same problem and i removed actionbar and it display perfectly.
      You should try

      • Haziq Shohaimi

        I have remove the action bar, but the green line is still there

    • Haziq Shohaimi

      Do we have any other solution?

  • Cahaya Alam

    Hi Ravi Tamada,
    I get this problem to, when first time launch and allow camera permission, scanner is black.. until the app closed and then it will running well. it just when ask permission.
    thanks before.. https://uploads.disquscdn.com/images/f5a1935dbfde2b4905e83ac861bd00c381be3378178fa2aa8bb1d0e15aca716f.png

    • Please check the library in the evening. Somebody fixed this issue and pushed the changes. I’ll deploy the newer version of the library and notify you once done.

    • The library is updated. Please get the latest library 1.1.5

      implementation ‘info.androidhive:barcode-reader:1.1.5’

  • Is there any GitHub page available of this library

    • The Github button is there at the beginning of the article.

  • Have you included the google vision dependency also? It’s required.

    • venkatesh kumar

      Yes included vision api version 11.0.2

      • Try latest version of play services libraries. make sure all the google services are using the same version. Clean the project and build again.

        • venkatesh kumar

          Thanks a lot bro.. That’s the issue(play service version mismatch) and fixed it

  • SHWETA GUPTA

    Hi Ravi, Useful Tutorial.
    My app require multilingual support while scanning QR code, like if i generated a QR code by using hindi text or some other language then scanner should scan that language text only. Hope you will find any way to do this. It would be helpful for me. Thanks in advance.

    • The scanner will always scans the QR Code. You have to decide whether to show next UI on qr is scanned or just ignore the scanned result if it’s not from the same language.

      Is it clear?

      • SHWETA GUPTA

        I am generating QR code by typing text from other language keyboard, its working fine. now i am going to scan that QR code from by using vision lib but it shows “?????” this string. i want to get back that language string.

  • Imran khan

    Hi Ravi,
    onScanned(Barcode barcode) is not invoking for me.
    any suggestions?

    • Imran khan

      I implemented inside fragment

  • Sindhuja K

    Sir, what is qrcode in drawable folder?

  • amir reza

    https://uploads.disquscdn.com/images/cea4c90b4e8b46d0d02df1ca32676c41068fdefa6c17024cbcbfd85fcac5a665.jpg

    Hi great tutorial
    1 how can i hide the green url in the box when its scanning?
    2 Why my camera in zoom?

  • Abay Amanzhol

    Hi Ravi, very informative. Can you share search.php to get idea of to generate QRcode. Thank You

    • Hi Abay

      I made search.php very simple as it’s not the main intent . It just opens the file and prints it’s content.

  • Przemohawryl

    Hey, I have a bug when i going back from scanning result. Moving line from scanner square escapes from him. This only happens when I’m turn back to ScanActivity from other Activity. What can i do with it?

  • Prathik Preman

    Hi Ravi, its a nice tutorial, is there any way to make use of front camera for scanning instead of back camera ?

  • nguyenthao88

    hi sir! how to fix camera not autofocus in google vision read qrcode? camera is blur when scan qrcode

  • Sreekar Ml

    hi ,

    • Yes it will. There is a callback to read multiple qr codes.

  • nguyenthao88

    hi Ravi Tamada!
    How to fix camera not autofocus in google vision read qrcode? camera is blur when scan qrcode.
    Please help me!

  • nguyenthao88

    Hi PaijoRX!
    Thanks you for Reply.
    You can send for me source code demo fix autofocus, I’m try but not success.
    Thanks you again.

  • Prabhakar Kumar

    Hi Ravi
    Can we set “use_flash” programmatically.

    • I think yes, need to recheck.

      • Prabhakar Kumar

        Hi Ravi
        if it possible please reply me as soon as possible.

        • I think I have removed flash programatically. The library has to be modified. Please explore the library.

  • maul

    HY RAVI!!
    can u tell me how to create barcode or barcode .jpg you have?

    • I used online service to generate them.
      http://www.barcode-generator.org/

      • maul

        hi ravy, can you explaind me about JSON which you used

        i need logic, because im try to learn with local database and in my logcat, jsonobject is show, but in my phone is not show

        this is my jsonobject :
        {“0”:[{“name”:”a2″,”poster”:”test2″,”duration”:”test2″,”rating”:”test2″,”released”:”true”,”genre”:”test2″,”price”:”test2″,”director”:”test2″}],”status”:1,”message”:”success”}

        • Are you there any errors in LogCat? How are you parsing the json?

          • maul

            i try to run your apps in my phone is good perform and nothing problem, but when i change database with my local database, i just use search logic, but i cant get result like your apps,

            in logcat, nothing errors, jsonobject has been read

            this is my search.php = https://pastebin.com/qn1fUB5H

            please help me

          • I am not clear what the problem is.

          • maulana hady c.s

            can you explain me, what are logic used for get jsonobject?

    • maul

      ravi, can u give me a code php search for learn,

      can u email me to maulanahady52467@gmail.com

      i hope u want to help me, thx

      • Hi Maul

        I used http://www.barcode-generator.org/ to generate the barcode images.

      • Vinoth Kumar

        Im facing the same error. I got json data successfully and converted the url link as qr code, while i scan the qrcode its shows me “No ticket Found”..

  • Brijesh

    Hi Ravi,
    Can you share barcode scan through gallery images ?

  • Emmanuel Wakey

    hi Ravi! please can you share the content of the https://api.androidhive.info/barcodes/search.php???

    • Hi

      I am just reading the file by its name and printing the json. Not reading the data from a database.

      <?php

      if(isset($_GET["code"]) && strlen($_GET["code"]) > 0 && file_exists('./'.$_GET["code"].'.json')){
      $code = $_GET['code'];
      $data = file_get_contents ('./'.$code.'.json');
      //$json = json_decode($data, TRUE);
      echo $data;
      }else{
      $data = [];
      $data['error'] = 'Barcode not found!';
      echo json_encode($data);
      }
      ?>

  • akin

    Hello Ravi ,

    Please am getting this error when I click scan

    Caused by: java.lang.ClassNotFoundException: Didn’t find class “com.google.android.gms.common.internal.safeparcel.zza”

    • akin

      found the problem my version with gms was the problem

  • Gajanand Gajanand

    there is no link for dunkirk_barcode..please update the link.

  • Gajanand Gajanand

    Hi Ravi please help me to scan 1D barcode scanners as well..

  • Eggy Sudianto

    Hi, why did not the camera show the real thing? but become wider?

  • Eggy Sudianto

    Hi, why the camera become stretch in my phone xiaomi mi 5 Android 7.0 API 24?
    https://uploads.disquscdn.com/images/de583e3cfd687de744c51ddb60c922ad82d201d8897cd03b7b7d62453768a64f.png

    and in my phone samsung galaxy core 2 API 19 Android 4.4.2 the have green screen and text https://uploads.disquscdn.com/images/baccf413e6d6f799add1def6933b437e897db71e31a400c492d86cd25387dcc7.jpg in qrcode scanner?

  • Vinoth Kumar

    I got json data successfully and converted the url link as qr code, while i scan the qrcode its shows me “No ticket Found”..
    Can any1 guide me plz

    • Eggy Sudianto

      make sure the phone can connect to your API. You can check manual using your browser

  • Mukund Pradeep

    Hello,
    How can I pause/stop the scanner after scanning one barcode and resume again after completing some task?
    Please Advice

  • Lloyd Ramos

    Hi Ravi, can you explain to me the server side

    4.1 The REST API
    To build this app we need a REST api to search through movie database by movie barcode. I have written a simple rest api to search for a movie by barcode. This takes predefined barcode value as query param and searches it in the db. Here are the few sample barcodes for testing.

    1. dn_barcode.jpg
    2. spiderman_barcode.jpg
    3. wonderwoman_barcode.jpg
    4. dunkirk_barcode.jpg

    Search Movie:
    Make GET request with the barcode value read.
    https://api.androidhive.info/barcodes/search.php?code=dunkirk

    Movie Result:
    The matched movie json will be given in the response.

    {
    “name”: “Dunkirk”,
    “poster”: “https://api.androidhive.info/barcodes/dunkirk.jpg”,
    “duration”: “1hr 46min”,
    “rating”: 4.6,
    “released”: true,
    “genre”: “Action”,
    “price”: “₹200”,
    “director”: “Christopher Nolan”
    }

    please?

    • Usually the server contains list of barcodes in database along with movie details. In android app, when a barcode is scanned, it contains a unique identifier / string. We need to send this string to our server, the server performs a search and gets the matched movie details. The url I have provided exactly does the same, but for now it has 4 movies only.

      You can learn more about REST API here
      https://www.androidhive.info/2014/01/how-to-create-rest-api-for-android-app-using-php-slim-and-mysql-day-12-2/

      • Lloyd Ramos

        Should I create a database for barcodes? or just place it i file manager of the server?

        • Usually it should be database only. For demo purpose (and avoid creating a database on my server), I have kept static files.

      • Lloyd Ramos

        Were do I place this
        “name”: “Dunkirk”,
        “poster”: “”,
        “duration”: “1hr 46min”,
        “rating”: 4.6,
        “released”: true,
        “genre”: “Action”,
        “price”: “₹200”,
        “director”: “Christopher Nolan”
        }

      • Lloyd Ramos

        Thank you Ravi for supporting me, One last favor, Can you explain to me on how to create my of qr code server and database.

        And the search.php, I placed it in server?

      • Lloyd Ramos

        Where should I place this, please answer me.
        {
        “name”: “Dunkirk”,
        “poster”: “”,
        “duration”: “1hr 46min”,
        “rating”: 4.6,
        “released”: true,
        “genre”: “Action”,
        “price”: “₹200”,
        “director”: “Christopher Nolan”
        }

      • Lloyd Ramos

        Thanks Ravi

  • Lloyd Ramos

    Guys can you help me on were and what are the things to do to connect my own database to android. I don’t get the server or database side.

  • Lloyd Ramos
  • Lloyd Ramos

    Please help me Ravi

  • Lloyd Ramos

    Ravi, can you share to me the rest api? or please help me or explain to me the db side of this proect?

  • Lloyd Ramos

    Hi guys anyone who could help me?

    Which url should I generate to qr code?
    1 http://psucampustour.arapangmedia.com/barcodes/main.json?
    2 http://psucampustour.arapangmedia.com/barcodes/main.json?

    Because after I scan the qr code its shows me “No ticket Found”..

    Anyone who could help me please?

  • Anitha

    Hi Ravi,
    Your tutorial was great.. I would like to use front camera for reading the QRCode, could you please help me for that?

  • Davi Borges

    don’t works neither apk file

  • Jerry Luis

    How to make the camera looks nice in portrait mode?
    if i use it in lanscape mode it looks normal but not in portrait mode like cropped view.

  • Jerry Luis

    Hi, how to use flash programatically and i don’t know how to explore your barcode reader library can you teach me how? thanks

  • Thanks for this library, but I have the same issue of strecthing camera preview 🙁