it.jaschke.alexandria.BarcodeReaderActivity.java Source code

Java tutorial

Introduction

Here is the source code for it.jaschke.alexandria.BarcodeReaderActivity.java

Source

package it.jaschke.alexandria;

import android.Manifest;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.vision.Detector;
import com.google.android.gms.vision.MultiProcessor;
import com.google.android.gms.vision.Tracker;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.CameraSource;
import com.google.android.gms.vision.barcode.BarcodeDetector;

import java.io.IOException;

import it.jaschke.alexandria.CameraPreview.CameraPreview;
import it.jaschke.alexandria.CameraPreview.GraphicOverlay;

/**
 * Activity for the multi-tracker app.  This app detects barcodes and displays the value with the
 * rear facing camera. During detection overlay graphics are drawn to indicate the position,
 * size, and ID of each barcode.
 */
public final class BarcodeReaderActivity extends AppCompatActivity {
    private static final String TAG = "Barcode-reader";

    // intent request code to handle updating play services if needed.
    private static final int RC_HANDLE_GMS = 9001;
    public static final String BarcodeObject = "Barcode";

    private CameraSource mCameraSource;
    private GraphicOverlay<BarcodeGraphic> mGraphicOverlay;
    private CameraPreview mPreview;

    private GestureDetector gestureDetector;

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.barcode_capture);

        mPreview = (CameraPreview) findViewById(R.id.camera_preview);
        mGraphicOverlay = (GraphicOverlay<BarcodeGraphic>) findViewById(R.id.graphic_overlay);

        gestureDetector = new GestureDetector(this, new CaptureGestureListener());

        createCameraSource();

    }

    /**
     * Override touch event to activate our gesture listener
     */
    @Override
    public boolean onTouchEvent(MotionEvent e) {
        boolean gesture = gestureDetector.onTouchEvent(e);
        return gesture || super.onTouchEvent(e);
    }

    private void createCameraSource() {
        Context context = getApplicationContext();

        // Set up multiprocessor to track multiple barcodes
        BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build();
        BarcodeTrackerFactory barcodeFactory = new BarcodeTrackerFactory(mGraphicOverlay);
        barcodeDetector.setProcessor(new MultiProcessor.Builder<>(barcodeFactory).build());

        if (!barcodeDetector.isOperational()) {
            Toast.makeText(this, R.string.barcode_down, Toast.LENGTH_LONG).show();
        }

        // build camera
        mCameraSource = new CameraSource.Builder(getApplicationContext(), barcodeDetector)
                .setFacing(CameraSource.CAMERA_FACING_BACK).setAutoFocusEnabled(true)
                .setRequestedPreviewSize(1600, 1024).setRequestedFps(15.0f).build();
    }

    /**
     * Restarts the camera.
     */
    @Override
    protected void onResume() {
        super.onResume();
        startCameraSource();
    }

    /**
     * Stops the camera.
     */
    @Override
    protected void onPause() {
        super.onPause();
        if (mPreview != null) {
            mPreview.stop();
        }
    }

    /**
     * Releases the resources associated with the camera source, the associated detectors, and the
     * rest of the processing pipeline.
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPreview != null) {
            mPreview.release();
        }
    }

    /**
     * Starts or restarts the camera source, if it exists.  If the camera source doesn't exist yet
     * (e.g., because onResume was called before the camera source was created), this will be called
     * again when the camera source is created.
     */
    private void startCameraSource() throws SecurityException {
        // check that the device has play services available.
        int code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(getApplicationContext());
        if (code != ConnectionResult.SUCCESS) {
            GoogleApiAvailability.getInstance().getErrorDialog(this, code, RC_HANDLE_GMS).show();
        }

        if (mCameraSource != null) {
            try {
                mPreview.start(mCameraSource);
            } catch (IOException e) {
                mCameraSource.release();
                mCameraSource = null;
            }
        }
    }

    /**
     * onTap is called to capture the oldest barcode currently detected and
     * return it to the caller.
     *
     * @param rawX - the raw position of the tap
     * @param rawY - the raw position of the tap.
     * @return true if the activity is ending.
     */
    private boolean onTap(float rawX, float rawY) {

        BarcodeGraphic graphic = mGraphicOverlay.getFirstGraphic();
        Barcode barcode = null;
        if (graphic != null) {
            barcode = graphic.getBarcode();
            if (barcode != null) {
                Intent data = new Intent();
                data.putExtra(BarcodeObject, barcode);
                setResult(CommonStatusCodes.SUCCESS, data);
                finish();
            }
        }
        return barcode != null;
    }

    /*
     * Copyright (C) The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */

    /**
     * Factory for creating a tracker and associated graphic to be associated with a new barcode.  The
     * multi-processor uses this factory to create barcode trackers as needed -- one for each barcode.
     */
    class BarcodeTrackerFactory implements MultiProcessor.Factory<Barcode> {
        private GraphicOverlay<BarcodeGraphic> mGraphicOverlay;

        BarcodeTrackerFactory(GraphicOverlay<BarcodeGraphic> barcodeGraphicOverlay) {
            mGraphicOverlay = barcodeGraphicOverlay;
        }

        @Override
        public Tracker<Barcode> create(Barcode barcode) {
            // Found a barcode to use. Make graphic.
            BarcodeGraphic graphic = new BarcodeGraphic(mGraphicOverlay);
            return new BarcodeGraphicTracker(mGraphicOverlay, graphic);
        }

    }

    /**
     * Graphic instance for rendering barcode position, size, and ID within an associated graphic
     * overlay view.
     */
    public class BarcodeGraphic extends GraphicOverlay.Graphic {

        private int mId;

        private final int COLOR_CHOICES[] = { Color.BLUE, Color.CYAN, Color.GREEN };

        private int mCurrentColorIndex = 0;

        private Paint mRectPaint;
        private Paint mTextPaint;
        private volatile Barcode mBarcode;

        BarcodeGraphic(GraphicOverlay overlay) {
            super(overlay);

            mCurrentColorIndex = (mCurrentColorIndex + 1) % COLOR_CHOICES.length;
            final int selectedColor = COLOR_CHOICES[mCurrentColorIndex];

            mRectPaint = new Paint();
            mRectPaint.setColor(selectedColor);
            mRectPaint.setStyle(Paint.Style.STROKE);
            mRectPaint.setStrokeWidth(4.0f);

            mTextPaint = new Paint();
            mTextPaint.setColor(selectedColor);
            mTextPaint.setTextSize(36.0f);
        }

        public int getId() {
            return mId;
        }

        public void setId(int id) {
            this.mId = id;
        }

        public Barcode getBarcode() {
            return mBarcode;
        }

        /**
         * Updates the barcode instance from the detection of the most recent frame.  Invalidates the
         * relevant portions of the overlay to trigger a redraw.
         */
        void updateItem(Barcode barcode) {
            mBarcode = barcode;
            postInvalidate();
        }

        /**
         * Draws the barcode annotations for position, size, and raw value on the supplied canvas.
         */
        @Override
        public void draw(Canvas canvas) {
            Barcode barcode = mBarcode;
            if (barcode == null) {
                return;
            }

            // Draws the bounding box around the barcode.
            RectF rect = new RectF(barcode.getBoundingBox());
            rect.left = translateX(rect.left);
            rect.top = translateY(rect.top);
            rect.right = translateX(rect.right);
            rect.bottom = translateY(rect.bottom);
            canvas.drawRect(rect, mRectPaint);

            // Draws a label at the bottom of the barcode indicate the barcode value that was detected.
            canvas.drawText(barcode.rawValue, rect.left, rect.bottom, mTextPaint);
        }
    }

    /**
     * Generic tracker which is used for tracking or reading a barcode (and can really be used for
     * any type of item).  This is used to receive newly detected items, add a graphical representation
     * to an overlay, update the graphics as the item changes, and remove the graphics when the item
     * goes away.
     */
    class BarcodeGraphicTracker extends Tracker<Barcode> {
        private GraphicOverlay<BarcodeGraphic> mOverlay;
        private BarcodeGraphic mGraphic;

        BarcodeGraphicTracker(GraphicOverlay<BarcodeGraphic> overlay, BarcodeGraphic graphic) {
            mOverlay = overlay;
            mGraphic = graphic;
        }

        /**
         * Start tracking the detected item instance within the item overlay.
         */
        @Override
        public void onNewItem(int id, Barcode item) {
            mGraphic.setId(id);
        }

        /**
         * Update the position/characteristics of the item within the overlay.
         */
        @Override
        public void onUpdate(Detector.Detections<Barcode> detectionResults, Barcode item) {
            mOverlay.add(mGraphic);
            mGraphic.updateItem(item);
        }

        /**
         * Hide the graphic when the corresponding object was not detected.  This can happen for
         * intermediate frames temporarily, for example if the object was momentarily blocked from
         * view.
         */
        @Override
        public void onMissing(Detector.Detections<Barcode> detectionResults) {
            mOverlay.remove(mGraphic);
        }

        /**
         * Called when the item is assumed to be gone for good. Remove the graphic annotation from
         * the overlay.
         */
        @Override
        public void onDone() {
            mOverlay.remove(mGraphic);
        }
    }

    private class CaptureGestureListener extends GestureDetector.SimpleOnGestureListener {

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            return onTap(e.getRawX(), e.getRawY()) || super.onSingleTapConfirmed(e);
        }
    }
}