From 76f6fe5193ad114f787c2863ca976fe9a485ecbf Mon Sep 17 00:00:00 2001 From: Mrigank Dembla Date: Wed, 27 Jul 2016 13:23:44 +0530 Subject: [PATCH 1/2] Add files via upload --- BarcodeCaptureActivity.java | 454 ++++++++++++++++++++++++++++++++++++ BarcodeGraphicTracker.java | 87 +++++++ BarcodeTrackerFactory.java | 51 ++++ activity_main.xml | 76 ++++++ strings.xml | 16 ++ 5 files changed, 684 insertions(+) create mode 100644 BarcodeCaptureActivity.java create mode 100644 BarcodeGraphicTracker.java create mode 100644 BarcodeTrackerFactory.java create mode 100644 activity_main.xml create mode 100644 strings.xml diff --git a/BarcodeCaptureActivity.java b/BarcodeCaptureActivity.java new file mode 100644 index 00000000..a68bbe80 --- /dev/null +++ b/BarcodeCaptureActivity.java @@ -0,0 +1,454 @@ +/* + * 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. + */ +package com.google.android.gms.samples.vision.barcodereader; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.hardware.Camera; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.Snackbar; +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.view.View; +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.samples.vision.barcodereader.ui.camera.CameraSource; +import com.google.android.gms.samples.vision.barcodereader.ui.camera.CameraSourcePreview; + +import com.google.android.gms.samples.vision.barcodereader.ui.camera.GraphicOverlay; +import com.google.android.gms.vision.MultiProcessor; +import com.google.android.gms.vision.barcode.Barcode; +import com.google.android.gms.vision.barcode.BarcodeDetector; + +import java.io.IOException; + +/** + * 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 BarcodeCaptureActivity 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; + + // permission request codes need to be < 256 + private static final int RC_HANDLE_CAMERA_PERM = 2; + + // constants used to pass extra data in the intent + public static final String AutoFocus = "AutoFocus"; + public static final String UseFlash = "UseFlash"; + public static final String AutoDetect = "AutoDetect"; + public static final String BarcodeObject = "Barcode"; + + private CameraSource mCameraSource; + private CameraSourcePreview mPreview; + private GraphicOverlay mGraphicOverlay; + + // helper objects for detecting taps and pinches. + private ScaleGestureDetector scaleGestureDetector; + private GestureDetector gestureDetector; + + /** + * Initializes the UI and creates the detector pipeline. + */ + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + setContentView(R.layout.barcode_capture); + + mPreview = (CameraSourcePreview) findViewById(R.id.preview); + mGraphicOverlay = (GraphicOverlay) findViewById(R.id.graphicOverlay); + + // read parameters from the intent used to launch the activity. + boolean autoFocus = getIntent().getBooleanExtra(AutoFocus, false); + boolean useFlash = getIntent().getBooleanExtra(UseFlash, false); + boolean autoDetect = getIntent().getBooleanExtra(AutoDetect,false); + + // Check for the camera permission before accessing the camera. If the + // permission is not granted yet, request permission. + int rc = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA); + if (rc == PackageManager.PERMISSION_GRANTED) { + createCameraSource(autoFocus, useFlash,autoDetect); + } else { + requestCameraPermission(); + } + + gestureDetector = new GestureDetector(this, new CaptureGestureListener()); + scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener()); + + Snackbar.make(mGraphicOverlay, "Tap to capture. Pinch/Stretch to zoom", + Snackbar.LENGTH_LONG) + .show(); + } + + /** + * Handles the requesting of the camera permission. This includes + * showing a "Snackbar" message of why the permission is needed then + * sending the request. + */ + private void requestCameraPermission() { + Log.w(TAG, "Camera permission is not granted. Requesting permission"); + + final String[] permissions = new String[]{Manifest.permission.CAMERA}; + + if (!ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.CAMERA)) { + ActivityCompat.requestPermissions(this, permissions, RC_HANDLE_CAMERA_PERM); + return; + } + + final Activity thisActivity = this; + + View.OnClickListener listener = new View.OnClickListener() { + @Override + public void onClick(View view) { + ActivityCompat.requestPermissions(thisActivity, permissions, + RC_HANDLE_CAMERA_PERM); + } + }; + + Snackbar.make(mGraphicOverlay, R.string.permission_camera_rationale, + Snackbar.LENGTH_INDEFINITE) + .setAction(R.string.ok, listener) + .show(); + } + + @Override + public boolean onTouchEvent(MotionEvent e) { + boolean b = scaleGestureDetector.onTouchEvent(e); + + boolean c = gestureDetector.onTouchEvent(e); + + return b || c || super.onTouchEvent(e); + } + + /** + * Creates and starts the camera. Note that this uses a higher resolution in comparison + * to other detection examples to enable the barcode detector to detect small barcodes + * at long distances. + * + * Suppressing InlinedApi since there is a check that the minimum version is met before using + * the constant. + */ + @SuppressLint("InlinedApi") + private void createCameraSource(boolean autoFocus, boolean useFlash, boolean autoDetect) { + Context context = getApplicationContext(); + + // A barcode detector is created to track barcodes. An associated multi-processor instance + // is set to receive the barcode detection results, track the barcodes, and maintain + // graphics for each barcode on screen. The factory is used by the multi-processor to + // create a separate tracker instance for each barcode. + BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build(); + BarcodeTrackerFactory barcodeFactory; + //if autodetect is disabled, barcode is detected on tap only + if(!autoDetect) { + barcodeFactory = new BarcodeTrackerFactory(mGraphicOverlay); + + } + else { + //autodetect is enabled, automatic detect barcode + barcodeFactory = new BarcodeTrackerFactory(mGraphicOverlay, new BarcodeGraphicTracker.BarcodeAutoDetectionListener() { + + + @Override + public void onNewBarcodeDetection(Barcode barcode) { + if (barcode != null) { + Intent data = new Intent(); + data.putExtra(BarcodeObject, barcode); + //setResult(CommonStatusCodes.SUCCESS, data); + if (getParent() == null) { + setResult(CommonStatusCodes.SUCCESS, data); + } else { + getParent().setResult(CommonStatusCodes.SUCCESS, data); + } + finish(); + } + Log.d("BarcodeDetected", barcode.displayValue); + } + }); + } + barcodeDetector.setProcessor( + new MultiProcessor.Builder<>(barcodeFactory).build()); + + + + + if (!barcodeDetector.isOperational()) { + // Note: The first time that an app using the barcode or face API is installed on a + // device, GMS will download a native libraries to the device in order to do detection. + // Usually this completes before the app is run for the first time. But if that + // download has not yet completed, then the above call will not detect any barcodes + // and/or faces. + // + // isOperational() can be used to check if the required native libraries are currently + // available. The detectors will automatically become operational once the library + // downloads complete on device. + Log.w(TAG, "Detector dependencies are not yet available."); + + // Check for low storage. If there is low storage, the native library will not be + // downloaded, so detection will not become operational. + IntentFilter lowstorageFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW); + boolean hasLowStorage = registerReceiver(null, lowstorageFilter) != null; + + if (hasLowStorage) { + Toast.makeText(this, R.string.low_storage_error, Toast.LENGTH_LONG).show(); + Log.w(TAG, getString(R.string.low_storage_error)); + } + } + + // Creates and starts the camera. Note that this uses a higher resolution in comparison + // to other detection examples to enable the barcode detector to detect small barcodes + // at long distances. + CameraSource.Builder builder = new CameraSource.Builder(getApplicationContext(), barcodeDetector) + .setFacing(CameraSource.CAMERA_FACING_BACK) + .setRequestedPreviewSize(1600, 1024) + .setRequestedFps(15.0f); + + // make sure that auto focus is an available option + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + builder = builder.setFocusMode( + autoFocus ? Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE : null); + } + + mCameraSource = builder + .setFlashMode(useFlash ? Camera.Parameters.FLASH_MODE_TORCH : null) + .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(); + } + } + + /** + * Callback for the result from requesting permissions. This method + * is invoked for every call on {@link #requestPermissions(String[], int)}. + *

+ * Note: It is possible that the permissions request interaction + * with the user is interrupted. In this case you will receive empty permissions + * and results arrays which should be treated as a cancellation. + *

+ * + * @param requestCode The request code passed in {@link #requestPermissions(String[], int)}. + * @param permissions The requested permissions. Never null. + * @param grantResults The grant results for the corresponding permissions + * which is either {@link PackageManager#PERMISSION_GRANTED} + * or {@link PackageManager#PERMISSION_DENIED}. Never null. + * @see #requestPermissions(String[], int) + */ + @Override + public void onRequestPermissionsResult(int requestCode, + @NonNull String[] permissions, + @NonNull int[] grantResults) { + if (requestCode != RC_HANDLE_CAMERA_PERM) { + Log.d(TAG, "Got unexpected permission result: " + requestCode); + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + return; + } + + if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + Log.d(TAG, "Camera permission granted - initialize the camera source"); + // we have permission, so create the camerasource + boolean autoFocus = getIntent().getBooleanExtra(AutoFocus,false); + boolean useFlash = getIntent().getBooleanExtra(UseFlash, false); + boolean autoDetect = getIntent().getBooleanExtra(AutoDetect, false); + + createCameraSource(autoFocus, useFlash,autoDetect); + return; + } + + Log.e(TAG, "Permission not granted: results len = " + grantResults.length + + " Result code = " + (grantResults.length > 0 ? grantResults[0] : "(empty)")); + + DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + finish(); + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("Multitracker sample") + .setMessage(R.string.no_camera_permission) + .setPositiveButton(R.string.ok, listener) + .show(); + } + + /** + * 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) { + Dialog dlg = + GoogleApiAvailability.getInstance().getErrorDialog(this, code, RC_HANDLE_GMS); + dlg.show(); + } + + if (mCameraSource != null) { + try { + mPreview.start(mCameraSource, mGraphicOverlay); + } catch (IOException e) { + Log.e(TAG, "Unable to start camera source.", 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) { + + //TODO: use the tap position to select the barcode. + 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(); + } + else { + Log.d(TAG, "barcode data is null"); + } + } + else { + Log.d(TAG,"no barcode detected"); + } + return barcode != null; + } + + private class CaptureGestureListener extends GestureDetector.SimpleOnGestureListener { + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + + return onTap(e.getRawX(), e.getRawY()) || super.onSingleTapConfirmed(e); + } + } + + private class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener { + + /** + * Responds to scaling events for a gesture in progress. + * Reported by pointer motion. + * + * @param detector The detector reporting the event - use this to + * retrieve extended info about event state. + * @return Whether or not the detector should consider this event + * as handled. If an event was not handled, the detector + * will continue to accumulate movement until an event is + * handled. This can be useful if an application, for example, + * only wants to update scaling factors if the change is + * greater than 0.01. + */ + @Override + public boolean onScale(ScaleGestureDetector detector) { + return false; + } + + /** + * Responds to the beginning of a scaling gesture. Reported by + * new pointers going down. + * + * @param detector The detector reporting the event - use this to + * retrieve extended info about event state. + * @return Whether or not the detector should continue recognizing + * this gesture. For example, if a gesture is beginning + * with a focal point outside of a region where it makes + * sense, onScaleBegin() may return false to ignore the + * rest of the gesture. + */ + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + return true; + } + + /** + * Responds to the end of a scale gesture. Reported by existing + * pointers going up. + *

+ * Once a scale has ended, {@link ScaleGestureDetector#getFocusX()} + * and {@link ScaleGestureDetector#getFocusY()} will return focal point + * of the pointers remaining on the screen. + * + * @param detector The detector reporting the event - use this to + * retrieve extended info about event state. + */ + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + mCameraSource.doZoom(detector.getScaleFactor()); + } + } +} diff --git a/BarcodeGraphicTracker.java b/BarcodeGraphicTracker.java new file mode 100644 index 00000000..4f43d0b2 --- /dev/null +++ b/BarcodeGraphicTracker.java @@ -0,0 +1,87 @@ +/* + * 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. + */ +package com.google.android.gms.samples.vision.barcodereader; + +import com.google.android.gms.samples.vision.barcodereader.ui.camera.GraphicOverlay; +import com.google.android.gms.vision.Detector; +import com.google.android.gms.vision.Tracker; +import com.google.android.gms.vision.barcode.Barcode; + +/** + * 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 { + private GraphicOverlay mOverlay; + private BarcodeGraphic mGraphic; + //custom listener for barcode detection + private BarcodeAutoDetectionListener barcodeAutoDetectionListener; + + + BarcodeGraphicTracker(GraphicOverlay 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); + if(barcodeAutoDetectionListener!=null){ + barcodeAutoDetectionListener.onNewBarcodeDetection(item); + } + } + + public void setNewDetectionListener(BarcodeAutoDetectionListener barcodeAutoDetectionListener){ + this.barcodeAutoDetectionListener = barcodeAutoDetectionListener; + } + + /** + * Update the position/characteristics of the item within the overlay. + */ + @Override + public void onUpdate(Detector.Detections 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 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); + } + + public interface BarcodeAutoDetectionListener{ + void onNewBarcodeDetection(Barcode barcode); + } +} diff --git a/BarcodeTrackerFactory.java b/BarcodeTrackerFactory.java new file mode 100644 index 00000000..f68bfe13 --- /dev/null +++ b/BarcodeTrackerFactory.java @@ -0,0 +1,51 @@ +/* + * 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. + */ +package com.google.android.gms.samples.vision.barcodereader; + +import com.google.android.gms.samples.vision.barcodereader.ui.camera.GraphicOverlay; +import com.google.android.gms.vision.MultiProcessor; +import com.google.android.gms.vision.Tracker; +import com.google.android.gms.vision.barcode.Barcode; + +/** + * 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 { + private GraphicOverlay mGraphicOverlay; + private BarcodeGraphicTracker.BarcodeAutoDetectionListener barcodeAutoDetectionListener; + + BarcodeTrackerFactory(GraphicOverlay barcodeGraphicOverlay){ + mGraphicOverlay = barcodeGraphicOverlay; + } + BarcodeTrackerFactory(GraphicOverlay barcodeGraphicOverlay, BarcodeGraphicTracker.BarcodeAutoDetectionListener barcodeAutoDetectionListener) { + mGraphicOverlay = barcodeGraphicOverlay; + this.barcodeAutoDetectionListener = barcodeAutoDetectionListener; + } + + @Override + public Tracker create(Barcode barcode) { + BarcodeGraphic graphic = new BarcodeGraphic(mGraphicOverlay); + BarcodeGraphicTracker tracker = new BarcodeGraphicTracker(mGraphicOverlay,graphic); + if(barcodeAutoDetectionListener!=null){ + tracker.setNewDetectionListener(barcodeAutoDetectionListener); + } + + return tracker; + } + +} + diff --git a/activity_main.xml b/activity_main.xml new file mode 100644 index 00000000..be9932f4 --- /dev/null +++ b/activity_main.xml @@ -0,0 +1,76 @@ + + + + + + + +