<classpathentry kind="lib" path="libs/org.openils_idl.jar"/>
<classpathentry kind="lib" path="libs/org.opensrf2_serialized_reg.jar"/>
<classpathentry kind="lib" path="libs/simple-xml-2.6.4.jar"/>
+ <classpathentry kind="lib" path="libs/zxing_barcode.jar"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="14" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET" />
+
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.VIBRATE"/>
+ <uses-permission android:name="android.permission.FLASHLIGHT"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-feature android:name="android.hardware.camera" />
+ <uses-feature android:name="android.hardware.camera.autofocus" />
+
<application
android:icon="@drawable/evergreen_launcher_icon"
android:label="@string/app_name"
<activity
android:name=".searchCatalog.AdvancedSearchActivity">
</activity>
+ <activity android:name=".barcodescan.CaptureActivity"
+ android:label="@string/app_name"
+ android:screenOrientation="landscape"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:windowSoftInputMode="stateAlwaysHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
<!-- Checkout Activities -->
<activity android:name=".accountAccess.checkout.ItemsCheckOutListView"></activity>
<gradient
android:angle="270"
android:endColor="@color/header_gradient_stop"
- android:startColor="@color/header_gradient_start" />
+ android:startColor="@color/header_gradient_start"
+
+ />
<corners
android:bottomLeftRadius="8dp"
android:angle="270"
android:centerColor="#00ffffff"
android:endColor="#00ffffff"
- android:startColor="#40ffffff" />
+ android:startColor="#40ffffff"
+ android:useLevel="false"
+ />
<corners
android:bottomLeftRadius="8dp"
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+
+ <FrameLayout android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <SurfaceView android:id="@+id/camera_view"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_centerInParent="true"/>
+
+ <org.evergreen.android.barcodescan.ViewfinderView
+ android:id="@+id/viewfinder_view"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"/>
+
+ <ImageView android:id="@+id/actionbar_bottom"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ />
+
+ </FrameLayout>
+</LinearLayout>
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
+ android:padding="4dip"
>
<include android:id="@+id/header_actionbar" layout="@layout/simple_actionbar"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/copy_information"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"
+ />
+
<LinearLayout
android:id="@+id/record_details_copy_information"
android:layout_width="fill_parent"
<!-- Search Details -->
<color name="dark">#000</color>
+
+
+
+ <!-- Barcode -->
+ <color name="contents_text">#ff000000</color>
+ <color name="encode_view">#ffffffff</color>
+ <color name="help_button_view">#ffcccccc</color>
+ <color name="help_view">#ff404040</color>
+ <color name="possible_result_points">#c0ffff00</color>
+ <color name="result_image_border">#ffffffff</color>
+ <color name="result_minor_text">#ffc0c0c0</color>
+ <color name="result_points">#c000ff00</color>
+ <color name="result_text">#ffffffff</color>
+ <color name="result_view">#b0000000</color>
+ <color name="sbc_header_text">#ff808080</color>
+ <color name="sbc_header_view">#ffffffff</color>
+ <color name="sbc_list_item">#fffff0e0</color>
+ <color name="sbc_layout_view">#ffffffff</color>
+ <color name="sbc_page_number_text">#ff000000</color>
+ <color name="sbc_snippet_text">#ff4b4b4b</color>
+ <color name="share_text">#ff000000</color>
+ <color name="status_view">#50000000</color>
+ <color name="status_text">#ffffffff</color>
+ <color name="transparent">#00000000</color>
+ <color name="viewfinder_frame">#ff000000</color>
+ <color name="viewfinder_laser">#ffff0000</color>
+ <color name="viewfinder_mask">#60000000</color>
+ <color name="destionation_color">#a0ff0000</color>
</resources>
<item type="id" name="actionbar_compat_item_refresh_progress" />
<item type="id" name="actionbar_compat_item_refresh" />
<item type="id" name="menu_refresh" />
+
+ <!-- Messages IDs -->
+ <item type="id" name="auto_focus"/>
+ <item type="id" name="decode"/>
+ <item type="id" name="decode_failed"/>
+ <item type="id" name="decode_succeeded"/>
+ <item type="id" name="launch_product_query"/>
+ <item type="id" name="quit"/>
+ <item type="id" name="restart_preview"/>
+ <item type="id" name="return_scan_result"/>
</resources>
<string name="cancel_button">Cancel</string>
<string name="connect_button">Connect</string>
+ <!-- Search -->
+
<string name="search_hint">What are you looking for?</string>
<string name="advanced_search">Search</string>
<string name="menu_button_library_hours">Library hours</string>
<string name="menu_button_application_preferences">Preferences</string>
-
+ <string name="copy_information"> Availability of the book :</string>
<string name="hello">Hello World, EvergreenAppActivity!</string>
<string name="app_name">EvergreenApp</string>
<string name="create">create</string>
<string name="bookbag_name">bookbag name</string>
<string name="add_button">add</string>
+
+
+ <!-- Camera -->
+ <string name="msg_camera_framework_bug">Sorry, the Android camera encountered a problem. You may need to restart the device.</string>
+ <string name="button_ok">OK</string>
</resources>
\ No newline at end of file
--- /dev/null
+package org.evergreen.android.barcodescan;
+
+import java.io.IOException;
+import java.util.Vector;
+
+import org.evergreen.android.R;
+import org.evergreen.android.barcodescan.camera.CameraManager;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.Menu;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.Result;
+
+public class CaptureActivity extends Activity implements SurfaceHolder.Callback {
+
+ private static final String TAG = CaptureActivity.class.getSimpleName();
+
+ private ViewfinderView viewfinderView;
+
+ private CaptureActivityHandler handler;
+
+ private CameraManager cameraManager;
+ private boolean hasSurface;
+ private Vector<BarcodeFormat> decodeFormats;
+ // private HistoryManager historyManager;
+ private Result lastResult;
+ private String characterSet;
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Remove title bar
+ this.requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ // Remove notification bar
+ this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN);
+
+ setContentView(R.layout.barcode_scan);
+
+ Log.d("BARCODE","Start application 1");
+ Window window = getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ // init camera manager
+ cameraManager = new CameraManager(getApplication());
+ hasSurface = false;
+ handler = null;
+
+ viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
+
+ viewfinderView.setCameraManager(cameraManager);
+ //database = new DBHelper(this);
+
+ Log.d("BARCODE","Start application 2");
+ Toast.makeText(this, "Hello", Toast.LENGTH_LONG);
+ }
+
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ SurfaceView surfaceView = (SurfaceView) findViewById(R.id.camera_view);
+ SurfaceHolder surfaceHolder = surfaceView.getHolder();
+ if (hasSurface) {
+ // The activity was paused but not stopped, so the surface still
+ // exists. Therefore
+ // surfaceCreated() won't be called, so init the camera here.
+ initCamera(surfaceHolder);
+ } else {
+ // Install the callback and wait for surfaceCreated() to init the
+ // camera.
+ surfaceHolder.addCallback(this);
+ surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+ }
+
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (handler != null) {
+ handler.quitSynchronously();
+ handler = null;
+ }
+ cameraManager.closeDriver();
+ }
+
+ public void surfaceCreated(SurfaceHolder holder) {
+ if (!hasSurface) {
+ hasSurface = true;
+ initCamera(holder);
+ }
+ }
+
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ hasSurface = false;
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {
+
+ }
+
+ private void initCamera(SurfaceHolder surfaceHolder) {
+ try {
+
+
+ cameraManager.openDriver(surfaceHolder);
+ // Creating the handler starts the preview, which can also throw a
+ // RuntimeException.
+ if (handler == null) {
+ //decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
+ handler = new CaptureActivityHandler(this, decodeFormats,
+ characterSet, cameraManager);
+ }
+ } catch (IOException ioe) {
+ Log.w(TAG, ioe);
+ displayFrameworkBugMessageAndExit("IOException");
+ } catch (RuntimeException e) {
+ // Barcode Scanner has seen crashes in the wild of this variety:
+ // java.?lang.?RuntimeException: Fail to connect to camera service
+ Log.w(TAG, "Unexpected error initializating camera", e);
+ displayFrameworkBugMessageAndExit("RuntimeException");
+ }
+ }
+
+ public Handler getHandler() {
+ return handler;
+ }
+
+ ViewfinderView getViewfinderView() {
+ return viewfinderView;
+ }
+
+
+ public void handleDecode(Result points) {
+ /*
+ float[] newPoints = new float[8];
+ int i = 0;
+ for (ResultPoint point : points.getPoints()) {
+ newPoints[i] = point.getX();
+ i++;
+ newPoints[i] = point.getY();
+ i++;
+ }
+ resultPoints.setResultPoints(newPoints);
+ resultPoints.setDestination(destinationPoint.refx,destinationPoint.refy);
+
+ resultPoints.invalidate();
+
+ //handleDecodeInternally(rawResult, resultHandler, barcode);
+ if (handler != null) {
+ handler.sendEmptyMessage(R.id.restart_preview);
+ }
+ */
+ /*
+ if (handler != null) {
+ handler.sendEmptyMessage(R.id.restart_preview);
+ }
+ */
+
+ }
+
+ private void displayFrameworkBugMessageAndExit(String info) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(getString(R.string.app_name));
+ builder.setMessage("[" + info + "] "
+ + getString(R.string.msg_camera_framework_bug));
+ builder.setPositiveButton(R.string.button_ok, new FinishListener(this));
+ builder.setOnCancelListener(new FinishListener(this));
+ builder.show();
+ }
+
+ public void drawViewfinder() {
+ // Draw image result
+
+ viewfinderView.drawViewfinder();
+ }
+
+ public void removePoints() {
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // TODO Auto-generated method stub
+ super.onCreateOptionsMenu(menu);
+
+ return true;
+ }
+
+ /**
+ * A valid barcode has been found, so give an indication of success and show the results.
+ *
+ * @param rawResult The contents of the barcode.
+ * @param barcode A greyscale bitmap of the camera data which was decoded.
+ */
+ public void handleDecode(Result rawResult, Bitmap barcode) {
+
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage("Code bar Message : " + rawResult.getText())
+ .setCancelable(false)
+ .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ //restart preview to decode more barcodes
+ if(handler != null){
+ handler.sendEmptyMessage(R.id.restart_preview);
+ }
+ }
+ });
+
+ AlertDialog alert = builder.create();
+ alert.show();
+ //Toast.makeText(this, rawResult.getText(), Toast.LENGTH_LONG).show();
+ Log.d("BARCODE","Value"+ rawResult.getText());
+
+ }
+
+}
--- /dev/null
+
+package org.evergreen.android.barcodescan;
+
+import java.util.Vector;
+
+import org.evergreen.android.R;
+import org.evergreen.android.barcodescan.camera.CameraManager;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.Result;
+
+/**
+ * This class handles all the messaging which comprises the state machine for capture.
+@
+ */
+public final class CaptureActivityHandler extends Handler {
+
+ private static final String TAG = CaptureActivityHandler.class.getSimpleName();
+
+ private final CaptureActivity activity;
+ private final DecodeThread decodeThread;
+ private final CameraManager cameraManager;
+ private State state;
+
+ private enum State {
+ PREVIEW,
+ SUCCESS,
+ DONE
+ }
+
+ CaptureActivityHandler(CaptureActivity activity, Vector<BarcodeFormat> decodeFormats,
+ String characterSet,CameraManager cameraManager) {
+ this.activity = activity;
+ decodeThread = new DecodeThread(activity, decodeFormats, characterSet,
+ new ViewfinderResultPointCallback(activity.getViewfinderView()), cameraManager);
+ decodeThread.start();
+ state = State.SUCCESS;
+
+ // Start ourselves capturing previews and decoding.
+ this.cameraManager = cameraManager;
+ cameraManager.startPreview();
+ restartPreviewAndDecode();
+ if (state == State.PREVIEW) {
+ this.cameraManager.requestAutoFocus(this, R.id.auto_focus);
+ }
+
+ }
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case R.id.auto_focus:
+ //Log.d(TAG, "Got auto-focus message");
+ // When one auto focus pass finishes, start another. This is the closest thing to
+
+
+ break;
+ case R.id.decode_succeeded:
+ Log.d(TAG, "Got decode succeeded message");
+ state = State.SUCCESS;
+
+
+ Bundle bundle = message.getData();
+ Bitmap barcode = bundle == null ? null :
+ (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
+
+ activity.handleDecode((Result) message.obj, barcode);
+ activity.handleDecode((Result) message.obj);
+
+ break;
+ case R.id.restart_preview:
+ restartPreviewAndDecode();
+
+ break;
+
+ case R.id.decode_failed:
+ // We're decoding as fast as possible, so when one decode fails, start another.
+ state = State.PREVIEW;
+ cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
+ activity.removePoints();
+
+ break;
+ case R.id.return_scan_result:
+ Log.d(TAG, "Got return scan result message");
+ activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
+ activity.finish();
+ break;
+ case R.id.launch_product_query:
+ Log.d(TAG, "Got product query message");
+ String url = (String) message.obj;
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ activity.startActivity(intent);
+ break;
+ }
+ }
+
+ public void quitSynchronously() {
+ state = State.DONE;
+ cameraManager.stopPreview();
+ Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit);
+ quit.sendToTarget();
+ try {
+ decodeThread.join();
+ } catch (InterruptedException e) {
+ // continue
+ }
+
+ // Be absolutely sure we don't send any queued up messages
+ removeMessages(R.id.decode_succeeded);
+ removeMessages(R.id.decode_failed);
+ }
+
+ private void restartPreviewAndDecode() {
+ if (state == State.SUCCESS) {
+ state = State.PREVIEW;
+ cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
+ cameraManager.requestAutoFocus(this, R.id.auto_focus);
+ activity.drawViewfinder();
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Vector;
+import java.util.regex.Pattern;
+
+import android.content.Intent;
+import android.net.Uri;
+import com.google.zxing.BarcodeFormat;
+
+final class DecodeFormatManager {
+
+ private static final Pattern COMMA_PATTERN = Pattern.compile(",");
+
+ static final Vector<BarcodeFormat> PRODUCT_FORMATS;
+ static final Vector<BarcodeFormat> ONE_D_FORMATS;
+ static final Vector<BarcodeFormat> QR_CODE_FORMATS;
+ static final Vector<BarcodeFormat> DATA_MATRIX_FORMATS;
+ static {
+ PRODUCT_FORMATS = new Vector<BarcodeFormat>(5);
+ PRODUCT_FORMATS.add(BarcodeFormat.UPC_A);
+ PRODUCT_FORMATS.add(BarcodeFormat.UPC_E);
+ PRODUCT_FORMATS.add(BarcodeFormat.EAN_13);
+ PRODUCT_FORMATS.add(BarcodeFormat.EAN_8);
+ PRODUCT_FORMATS.add(BarcodeFormat.RSS_14);
+ ONE_D_FORMATS = new Vector<BarcodeFormat>(PRODUCT_FORMATS.size() + 4);
+ ONE_D_FORMATS.addAll(PRODUCT_FORMATS);
+ ONE_D_FORMATS.add(BarcodeFormat.CODE_39);
+ ONE_D_FORMATS.add(BarcodeFormat.CODE_93);
+ ONE_D_FORMATS.add(BarcodeFormat.CODE_128);
+ ONE_D_FORMATS.add(BarcodeFormat.ITF);
+ QR_CODE_FORMATS = new Vector<BarcodeFormat>(1);
+ QR_CODE_FORMATS.add(BarcodeFormat.QR_CODE);
+ DATA_MATRIX_FORMATS = new Vector<BarcodeFormat>(1);
+ DATA_MATRIX_FORMATS.add(BarcodeFormat.DATA_MATRIX);
+ }
+
+ private DecodeFormatManager() {}
+
+ static Vector<BarcodeFormat> parseDecodeFormats(Intent intent) {
+ List<String> scanFormats = null;
+ String scanFormatsString = intent.getStringExtra(Intents.Scan.FORMATS);
+ if (scanFormatsString != null) {
+ scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString));
+ }
+ return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE));
+ }
+
+ static Vector<BarcodeFormat> parseDecodeFormats(Uri inputUri) {
+ List<String> formats = inputUri.getQueryParameters(Intents.Scan.FORMATS);
+ if (formats != null && formats.size() == 1 && formats.get(0) != null){
+ formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0)));
+ }
+ return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE));
+ }
+
+ private static Vector<BarcodeFormat> parseDecodeFormats(Iterable<String> scanFormats,
+ String decodeMode) {
+ if (scanFormats != null) {
+ Vector<BarcodeFormat> formats = new Vector<BarcodeFormat>();
+ try {
+ for (String format : scanFormats) {
+ formats.add(BarcodeFormat.valueOf(format));
+ }
+ return formats;
+ } catch (IllegalArgumentException iae) {
+ // ignore it then
+ }
+ }
+ if (decodeMode != null) {
+ if (Intents.Scan.PRODUCT_MODE.equals(decodeMode)) {
+ return PRODUCT_FORMATS;
+ }
+ if (Intents.Scan.QR_CODE_MODE.equals(decodeMode)) {
+ return QR_CODE_FORMATS;
+ }
+ if (Intents.Scan.DATA_MATRIX_MODE.equals(decodeMode)) {
+ return DATA_MATRIX_FORMATS;
+ }
+ if (Intents.Scan.ONE_D_MODE.equals(decodeMode)) {
+ return ONE_D_FORMATS;
+ }
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan;
+
+import java.util.Hashtable;
+import org.evergreen.android.R;
+import org.evergreen.android.barcodescan.camera.CameraManager;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import com.google.zxing.BinaryBitmap;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.MultiFormatReader;
+import com.google.zxing.ReaderException;
+import com.google.zxing.Result;
+import com.google.zxing.common.HybridBinarizer;
+
+final class DecodeHandler extends Handler {
+
+ private static final String TAG = DecodeHandler.class.getSimpleName();
+
+ //Activity used for communication with her's handle
+ private final CaptureActivity activity;
+ private CameraManager cameraManager;
+ //Reader used to decode
+ private final MultiFormatReader multiFormatReader;
+
+ //running state of this decode thread
+ private boolean running = true;
+
+ DecodeHandler(CaptureActivity activity, Hashtable<DecodeHintType, Object> hints, CameraManager cameraManager) {
+ multiFormatReader = new MultiFormatReader();
+ multiFormatReader.setHints(hints);
+ this.activity = activity;
+ this.cameraManager = cameraManager;
+ }
+
+ /**
+ * Method handles messages obtained
+ *
+ */
+ @Override
+ public void handleMessage(Message message) {
+ if (!running) {
+ return;
+ //if thread is not running do nothing
+ }
+ switch (message.what) {
+ case R.id.decode:
+ decode((byte[]) message.obj, message.arg1, message.arg2);
+ break;
+ case R.id.quit:
+ //quit, set running false
+ running = false;
+ Looper.myLooper().quit();
+ break;
+ }
+ }
+
+
+ /**
+ * Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
+ * reuse the same reader objects from one decode to the next.
+ *
+ * @param data The YUV preview frame.
+ * @param width The width of the preview frame.
+ * @param height The height of the preview frame.
+ */
+ private void decode(byte[] data, int width, int height) {
+ long start = System.currentTimeMillis();
+ Result rawResult = null;
+ PlanarYUVLuminanceSource source = cameraManager.buildLuminanceSource(data, width, height);
+ if (source != null) {
+ BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
+ try {
+ rawResult = multiFormatReader.decodeWithState(bitmap);
+ } catch (ReaderException re) {
+ // continue
+ } finally {
+ multiFormatReader.reset();
+ }
+ }
+
+ Handler handler = activity.getHandler();
+ if (rawResult != null) {
+ // Don't log the barcode contents for security.
+ long end = System.currentTimeMillis();
+ Log.d(TAG, "Found barcode in " + (end - start) + " ms");
+ if (handler != null) {
+ Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult);
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
+ message.setData(bundle);
+ message.sendToTarget();
+ }
+ } else {
+ if (handler != null) {
+ Message message = Message.obtain(handler, R.id.decode_failed);
+ message.sendToTarget();
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.ResultPointCallback;
+
+import android.content.SharedPreferences;
+import android.os.Handler;
+import android.os.Looper;
+import android.preference.PreferenceManager;
+
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.concurrent.CountDownLatch;
+
+import org.evergreen.android.barcodescan.camera.CameraManager;
+
+/**
+ * This thread does all the heavy lifting of decoding the images.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+final class DecodeThread extends Thread {
+
+ public static final String BARCODE_BITMAP = "barcode_bitmap";
+
+ private final CaptureActivity activity;
+ private final Hashtable<DecodeHintType, Object> hints;
+ private Handler handler;
+ private final CountDownLatch handlerInitLatch;
+ private CameraManager cameraManager;
+ DecodeThread(CaptureActivity activity,
+ Vector<BarcodeFormat> decodeFormats,
+ String characterSet,
+ ResultPointCallback resultPointCallback, CameraManager cameraManager) {
+
+ this.activity = activity;
+ handlerInitLatch = new CountDownLatch(1);
+ this.cameraManager = cameraManager;
+ hints = new Hashtable<DecodeHintType, Object>(3);
+
+
+
+ // The prefs can't change while the thread is running, so pick them up once here.
+ if (decodeFormats == null || decodeFormats.isEmpty()) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
+ decodeFormats = new Vector<BarcodeFormat>();
+ if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_1D, true)) {
+ decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
+ }
+ /*
+ if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_QR, true)) {
+ decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
+ }
+ if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_DATA_MATRIX, true)) {
+ decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
+ }
+ */
+ }
+ hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
+
+ if (characterSet != null) {
+ hints.put(DecodeHintType.CHARACTER_SET, characterSet);
+ }
+ hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback);
+ }
+
+ Handler getHandler() {
+ try {
+ handlerInitLatch.await();
+ } catch (InterruptedException ie) {
+ // continue?
+ }
+ return handler;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ handler = new DecodeHandler(activity, hints, cameraManager);
+ handlerInitLatch.countDown();
+ Looper.loop();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+
+/**
+ * Simple listener used to exit the app in a few cases.
+ *
+ * @author Sean Owen
+ */
+public final class FinishListener
+ implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener, Runnable {
+
+ private final Activity activityToFinish;
+
+ public FinishListener(Activity activityToFinish) {
+ this.activityToFinish = activityToFinish;
+ }
+
+ public void onCancel(DialogInterface dialogInterface) {
+ run();
+ }
+
+ public void onClick(DialogInterface dialogInterface, int i) {
+ run();
+ }
+
+ public void run() {
+ activityToFinish.finish();
+ }
+
+}
--- /dev/null
+package org.evergreen.android.barcodescan;\r
+\r
+import android.content.Context;\r
+import android.graphics.Color;\r
+import android.widget.TextView;\r
+import android.widget.Toast;\r
+\r
+/**\r
+ * \r
+ * @author George Oprina\r
+ * \r
+ * 08.06.2011\r
+ */\r
+\r
+public class Functions {\r
+\r
+ // makes toast length short\r
+ public static void makeToast(String s, Context c) {\r
+ CharSequence text = s;\r
+ int duration = Toast.LENGTH_SHORT;\r
+\r
+ Toast toast = Toast.makeText(c, text, duration);\r
+ toast.show();\r
+ }\r
+\r
+ // makes toast selectable length\r
+ public static void makeToast(String s, Context c, int length) {\r
+ CharSequence text = s;\r
+ int duration = Toast.LENGTH_SHORT;\r
+\r
+ if (length == 1)\r
+ duration = Toast.LENGTH_LONG;\r
+\r
+ Toast toast = Toast.makeText(c, text, duration);\r
+ toast.show();\r
+ }\r
+\r
+ // makes text view from string\r
+ public static TextView makeTextView(String s, Context c) {\r
+ TextView text = new TextView(c);\r
+ text.setBackgroundColor(Color.WHITE);\r
+ text.setText(s);\r
+ text.setTextColor(Color.BLACK);\r
+ return text;\r
+ }\r
+\r
+ // thread sleep\r
+ public static void sleep(int msec) {\r
+ try {\r
+ Thread.sleep(msec);\r
+ } catch (InterruptedException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+\r
+}\r
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan;
+
+/**
+ * This class provides the constants to use when sending an Intent to Barcode Scanner.
+ * These strings are effectively API and cannot be changed.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class Intents {
+ private Intents() {
+ }
+
+ public static final class Scan {
+ /**
+ * Send this intent to open the Barcodes app in scanning mode, find a barcode, and return
+ * the results.
+ */
+ public static final String ACTION = "com.google.zxing.client.android.SCAN";
+
+ /**
+ * By default, sending Scan.ACTION will decode all barcodes that we understand. However it
+ * may be useful to limit scanning to certain formats. Use Intent.putExtra(MODE, value) with
+ * one of the values below.
+ *
+ * Setting this is effectively shorthand for setting explicit formats with {@link #FORMATS}.
+ * It is overridden by that setting.
+ */
+ public static final String MODE = "SCAN_MODE";
+
+ /**
+ * Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get
+ * prices, reviews, etc. for products.
+ */
+ public static final String PRODUCT_MODE = "PRODUCT_MODE";
+
+ /**
+ * Decode only 1D barcodes.
+ */
+ public static final String ONE_D_MODE = "ONE_D_MODE";
+
+ /**
+ * Decode only QR codes.
+ */
+ public static final String QR_CODE_MODE = "QR_CODE_MODE";
+
+ /**
+ * Decode only Data Matrix codes.
+ */
+ public static final String DATA_MATRIX_MODE = "DATA_MATRIX_MODE";
+
+ /**
+ * Comma-separated list of formats to scan for. The values must match the names of
+ * {@link com.google.zxing.BarcodeFormat}s, e.g. {@link com.google.zxing.BarcodeFormat#EAN_13}.
+ * Example: "EAN_13,EAN_8,QR_CODE"
+ *
+ * This overrides {@link #MODE}.
+ */
+ public static final String FORMATS = "SCAN_FORMATS";
+
+ /**
+ * @see com.google.zxing.DecodeHintType#CHARACTER_SET
+ */
+ public static final String CHARACTER_SET = "CHARACTER_SET";
+
+ /**
+ * Optional parameters to specify the width and height of the scanning rectangle in pixels.
+ * The app will try to honor these, but will clamp them to the size of the preview frame.
+ * You should specify both or neither, and pass the size as an int.
+ */
+ public static final String WIDTH = "SCAN_WIDTH";
+ public static final String HEIGHT = "SCAN_HEIGHT";
+
+ /**
+ * If a barcode is found, Barcodes returns RESULT_OK to onActivityResult() of the app which
+ * requested the scan via startSubActivity(). The barcodes contents can be retrieved with
+ * intent.getStringExtra(RESULT). If the user presses Back, the result code will be
+ * RESULT_CANCELED.
+ */
+ public static final String RESULT = "SCAN_RESULT";
+
+ /**
+ * Call intent.getStringExtra(RESULT_FORMAT) to determine which barcode format was found.
+ * See Contents.Format for possible values.
+ */
+ public static final String RESULT_FORMAT = "SCAN_RESULT_FORMAT";
+
+ /**
+ * Call intent.getByteArrayExtra(RESULT_BYTES) to get a {@link byte[]} of raw bytes in the
+ * barcode, if available.
+ */
+ public static final String RESULT_BYTES = "SCAN_RESULT_BYTES";
+
+ /**
+ * Setting this to false will not save scanned codes in the history.
+ */
+ public static final String SAVE_HISTORY = "SAVE_HISTORY";
+
+ private Scan() {
+ }
+ }
+
+ public static final class Encode {
+ /**
+ * Send this intent to encode a piece of data as a QR code and display it full screen, so
+ * that another person can scan the barcode from your screen.
+ */
+ public static final String ACTION = "com.google.zxing.client.android.ENCODE";
+
+ /**
+ * The data to encode. Use Intent.putExtra(DATA, data) where data is either a String or a
+ * Bundle, depending on the type and format specified. Non-QR Code formats should
+ * just use a String here. For QR Code, see Contents for details.
+ */
+ public static final String DATA = "ENCODE_DATA";
+
+ /**
+ * The type of data being supplied if the format is QR Code. Use
+ * Intent.putExtra(TYPE, type) with one of Contents.Type.
+ */
+ public static final String TYPE = "ENCODE_TYPE";
+
+ /**
+ * The barcode format to be displayed. If this isn't specified or is blank,
+ * it defaults to QR Code. Use Intent.putExtra(FORMAT, format), where
+ * format is one of Contents.Format.
+ */
+ public static final String FORMAT = "ENCODE_FORMAT";
+
+ private Encode() {
+ }
+ }
+
+ public static final class SearchBookContents {
+ /**
+ * Use Google Book Search to search the contents of the book provided.
+ */
+ public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS";
+
+ /**
+ * The book to search, identified by ISBN number.
+ */
+ public static final String ISBN = "ISBN";
+
+ /**
+ * An optional field which is the text to search for.
+ */
+ public static final String QUERY = "QUERY";
+
+ private SearchBookContents() {
+ }
+ }
+
+ public static final class WifiConnect {
+ /**
+ * Internal intent used to trigger connection to a wi-fi network.
+ */
+ public static final String ACTION = "com.google.zxing.client.android.WIFI_CONNECT";
+
+ /**
+ * The network to connect to, all the configuration provided here.
+ */
+ public static final String SSID = "SSID";
+
+ /**
+ * The network to connect to, all the configuration provided here.
+ */
+ public static final String TYPE = "TYPE";
+
+ /**
+ * The network to connect to, all the configuration provided here.
+ */
+ public static final String PASSWORD = "PASSWORD";
+
+ private WifiConnect() {
+ }
+ }
+
+ public static final class Share {
+ /**
+ * Give the user a choice of items to encode as a barcode, then render it as a QR Code and
+ * display onscreen for a friend to scan with their phone.
+ */
+ public static final String ACTION = "com.google.zxing.client.android.SHARE";
+
+ private Share() {
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright 2009 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan;
+
+import com.google.zxing.LuminanceSource;
+
+import android.graphics.Bitmap;
+
+/**
+ * This object extends LuminanceSource around an array of YUV data returned from the camera driver,
+ * with the option to crop to a rectangle within the full data. This can be used to exclude
+ * superfluous pixels around the perimeter and speed up decoding.
+ *
+ * It works for any pixel format where the Y channel is planar and appears first, including
+ * YCbCr_420_SP and YCbCr_422_SP.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class PlanarYUVLuminanceSource extends LuminanceSource {
+
+ private final byte[] yuvData;
+ private final int dataWidth;
+ private final int dataHeight;
+ private final int left;
+ private final int top;
+
+ public PlanarYUVLuminanceSource(byte[] yuvData, int dataWidth, int dataHeight, int left, int top,
+ int width, int height, boolean reverseHorizontal) {
+ super(width, height);
+
+ if (left + width > dataWidth || top + height > dataHeight) {
+ throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
+ }
+
+ this.yuvData = yuvData;
+ this.dataWidth = dataWidth;
+ this.dataHeight = dataHeight;
+ this.left = left;
+ this.top = top;
+ if (reverseHorizontal) {
+ reverseHorizontal(width, height);
+ }
+ }
+
+ @Override
+ public byte[] getRow(int y, byte[] row) {
+ if (y < 0 || y >= getHeight()) {
+ throw new IllegalArgumentException("Requested row is outside the image: " + y);
+ }
+ int width = getWidth();
+ if (row == null || row.length < width) {
+ row = new byte[width];
+ }
+ int offset = (y + top) * dataWidth + left;
+ System.arraycopy(yuvData, offset, row, 0, width);
+ return row;
+ }
+
+ @Override
+ public byte[] getMatrix() {
+ int width = getWidth();
+ int height = getHeight();
+
+ // If the caller asks for the entire underlying image, save the copy and give them the
+ // original data. The docs specifically warn that result.length must be ignored.
+ if (width == dataWidth && height == dataHeight) {
+ return yuvData;
+ }
+
+ int area = width * height;
+ byte[] matrix = new byte[area];
+ int inputOffset = top * dataWidth + left;
+
+ // If the width matches the full width of the underlying data, perform a single copy.
+ if (width == dataWidth) {
+ System.arraycopy(yuvData, inputOffset, matrix, 0, area);
+ return matrix;
+ }
+
+ // Otherwise copy one cropped row at a time.
+ byte[] yuv = yuvData;
+ for (int y = 0; y < height; y++) {
+ int outputOffset = y * width;
+ System.arraycopy(yuv, inputOffset, matrix, outputOffset, width);
+ inputOffset += dataWidth;
+ }
+ return matrix;
+ }
+
+ @Override
+ public boolean isCropSupported() {
+ return true;
+ }
+
+ public Bitmap renderCroppedGreyscaleBitmap() {
+ int width = getWidth();
+ int height = getHeight();
+ int[] pixels = new int[width * height];
+ byte[] yuv = yuvData;
+ int inputOffset = top * dataWidth + left;
+
+ for (int y = 0; y < height; y++) {
+ int outputOffset = y * width;
+ for (int x = 0; x < width; x++) {
+ int grey = yuv[inputOffset + x] & 0xff;
+ pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101);
+ }
+ inputOffset += dataWidth;
+ }
+
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
+ return bitmap;
+ }
+
+ private void reverseHorizontal(int width, int height) {
+ byte[] yuvData = this.yuvData;
+ for (int y = 0, rowStart = top * dataWidth + left; y < height; y++, rowStart += dataWidth) {
+ int middle = rowStart + width / 2;
+ for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) {
+ byte temp = yuvData[x1];
+ yuvData[x1] = yuvData[x2];
+ yuvData[x2] = temp;
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan;
+
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * The main settings activity.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class PreferencesActivity extends PreferenceActivity
+ implements OnSharedPreferenceChangeListener {
+
+ public static final String KEY_DECODE_1D = "preferences_decode_1D";
+ public static final String KEY_DECODE_QR = "preferences_decode_QR";
+ public static final String KEY_DECODE_DATA_MATRIX = "preferences_decode_Data_Matrix";
+ public static final String KEY_CUSTOM_PRODUCT_SEARCH = "preferences_custom_product_search";
+
+ public static final String KEY_REVERSE_IMAGE = "preferences_reverse_image";
+ public static final String KEY_PLAY_BEEP = "preferences_play_beep";
+ public static final String KEY_VIBRATE = "preferences_vibrate";
+ public static final String KEY_COPY_TO_CLIPBOARD = "preferences_copy_to_clipboard";
+ public static final String KEY_FRONT_LIGHT = "preferences_front_light";
+ public static final String KEY_BULK_MODE = "preferences_bulk_mode";
+ public static final String KEY_REMEMBER_DUPLICATES = "preferences_remember_duplicates";
+ public static final String KEY_SUPPLEMENTAL = "preferences_supplemental";
+
+ public static final String KEY_HELP_VERSION_SHOWN = "preferences_help_version_shown";
+ public static final String KEY_NOT_OUR_RESULTS_SHOWN = "preferences_not_out_results_shown";
+
+ private CheckBoxPreference decode1D;
+ private CheckBoxPreference decodeQR;
+ private CheckBoxPreference decodeDataMatrix;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ // addPreferencesFromResource(R.xml.preferences);
+
+ PreferenceScreen preferences = getPreferenceScreen();
+ preferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+ decode1D = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_1D);
+ decodeQR = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_QR);
+ decodeDataMatrix = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_DATA_MATRIX);
+ disableLastCheckedPref();
+ }
+
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ disableLastCheckedPref();
+ }
+
+ private void disableLastCheckedPref() {
+ Collection<CheckBoxPreference> checked = new ArrayList<CheckBoxPreference>(3);
+ if (decode1D.isChecked()) {
+ checked.add(decode1D);
+ }
+ if (decodeQR.isChecked()) {
+ checked.add(decodeQR);
+ }
+ if (decodeDataMatrix.isChecked()) {
+ checked.add(decodeDataMatrix);
+ }
+ boolean disable = checked.size() < 2;
+ CheckBoxPreference[] checkBoxPreferences = {decode1D, decodeQR, decodeDataMatrix};
+ for (CheckBoxPreference pref : checkBoxPreferences) {
+ pref.setEnabled(!(disable && checked.contains(pref)));
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2009 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan;
+
+import com.google.zxing.ResultPoint;
+import com.google.zxing.ResultPointCallback;
+
+final class ViewfinderResultPointCallback implements ResultPointCallback {
+
+ private final ViewfinderView viewfinderView;
+
+ ViewfinderResultPointCallback(ViewfinderView viewfinderView) {
+ this.viewfinderView = viewfinderView;
+ }
+
+ public void foundPossibleResultPoint(ResultPoint point) {
+ viewfinderView.addPossibleResultPoint(point);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.evergreen.android.R;
+import org.evergreen.android.barcodescan.camera.CameraManager;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.google.zxing.ResultPoint;
+
+/**
+ * This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
+ * transparency outside it, as well as the laser scanner animation and result points.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class ViewfinderView extends View {
+
+ private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
+ private static final long ANIMATION_DELAY = 80L;
+ private static final int CURRENT_POINT_OPACITY = 0xA0;
+ private static final int MAX_RESULT_POINTS = 20;
+ private static final int POINT_SIZE = 6;
+
+ private CameraManager cameraManager;
+ private final Paint paint;
+ private Bitmap resultBitmap;
+ private int maskColor;
+ private int resultColor;
+ private int frameColor;
+ private int laserColor;
+ private int resultPointColor;
+ private int scannerAlpha;
+ private List<ResultPoint> possibleResultPoints;
+ private List<ResultPoint> lastPossibleResultPoints;
+
+ // This constructor is used when the class is built from an XML resource.
+ public ViewfinderView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ // Initialize these once for performance rather than calling them every time in onDraw().
+ paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ Resources resources = getResources();
+ maskColor = resources.getColor(R.color.viewfinder_mask);
+ resultColor = resources.getColor(R.color.result_view);
+ frameColor = resources.getColor(R.color.viewfinder_frame);
+ laserColor = resources.getColor(R.color.viewfinder_laser);
+ resultPointColor = resources.getColor(R.color.possible_result_points);
+ scannerAlpha = 0;
+ possibleResultPoints = new ArrayList<ResultPoint>(5);
+ lastPossibleResultPoints = null;
+ }
+
+ public void setCameraManager(CameraManager cameraManager) {
+ this.cameraManager = cameraManager;
+ }
+
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ Rect frame = cameraManager.getFramingRect();
+ if (frame == null) {
+ return;
+ }
+ int width = canvas.getWidth();
+ int height = canvas.getHeight();
+
+ // Draw the exterior (i.e. outside the framing rect) darkened
+ paint.setColor(resultBitmap != null ? resultColor : maskColor);
+
+ canvas.drawRect(0, 0, width, frame.top, paint);
+ canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
+ canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
+ canvas.drawRect(0, frame.bottom + 1, width, height, paint);
+
+ if (resultBitmap != null) {
+ // Draw the opaque result bitmap over the scanning rectangle
+ paint.setAlpha(CURRENT_POINT_OPACITY);
+ canvas.drawBitmap(resultBitmap, null, frame, paint);
+ } else {
+
+ // Draw a two pixel solid black border inside the framing rect
+ paint.setColor(frameColor);
+ canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
+ canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
+ canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
+ canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);
+
+ // Draw a red "laser scanner" line through the middle to show decoding is active
+ paint.setColor(laserColor);
+ paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
+ scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
+ int middle = frame.height() / 2 + frame.top;
+ canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
+
+ Rect previewFrame = cameraManager.getFramingRectInPreview();
+ float scaleX = frame.width() / (float) previewFrame.width();
+ float scaleY = frame.height() / (float) previewFrame.height();
+
+ List<ResultPoint> currentPossible = possibleResultPoints;
+ List<ResultPoint> currentLast = lastPossibleResultPoints;
+ int frameLeft = frame.left;
+ int frameTop = frame.top;
+ if (currentPossible.isEmpty()) {
+ lastPossibleResultPoints = null;
+ } else {
+ possibleResultPoints = new ArrayList<ResultPoint>(5);
+ lastPossibleResultPoints = currentPossible;
+ paint.setAlpha(CURRENT_POINT_OPACITY);
+ paint.setColor(resultPointColor);
+ synchronized (currentPossible) {
+ for (ResultPoint point : currentPossible) {
+ canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
+ frameTop + (int) (point.getY() * scaleY),
+ POINT_SIZE, paint);
+ }
+ }
+ }
+ if (currentLast != null) {
+ paint.setAlpha(CURRENT_POINT_OPACITY / 2);
+ paint.setColor(resultPointColor);
+ synchronized (currentLast) {
+ float radius = POINT_SIZE / 2.0f;
+ for (ResultPoint point : currentLast) {
+ canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
+ frameTop + (int) (point.getY() * scaleY),
+ radius, paint);
+ }
+ }
+ }
+
+ // Request another update at the animation interval, but only repaint the laser line,
+ // not the entire viewfinder mask.
+ postInvalidateDelayed(ANIMATION_DELAY,
+ frame.left - POINT_SIZE,
+ frame.top - POINT_SIZE,
+ frame.right + POINT_SIZE,
+ frame.bottom + POINT_SIZE);
+ }
+ }
+
+ public void drawViewfinder() {
+ Bitmap resultBitmap = this.resultBitmap;
+ this.resultBitmap = null;
+ if (resultBitmap != null) {
+ resultBitmap.recycle();
+ }
+ invalidate();
+ }
+
+ /**
+ * Draw a bitmap with the result points highlighted instead of the live scanning display.
+ *
+ * @param barcode An image of the decoded barcode.
+ */
+ public void drawResultBitmap(Bitmap barcode) {
+ resultBitmap = barcode;
+ invalidate();
+ }
+
+ public void addPossibleResultPoint(ResultPoint point) {
+ List<ResultPoint> points = possibleResultPoints;
+ synchronized (points) {
+ points.add(point);
+ int size = points.size();
+ if (size > MAX_RESULT_POINTS) {
+ // trim it
+ points.subList(0, size - MAX_RESULT_POINTS / 2).clear();
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan.camera;
+
+import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+final class AutoFocusCallback implements Camera.AutoFocusCallback {
+
+ private static final String TAG = AutoFocusCallback.class.getSimpleName();
+
+ private static final long AUTOFOCUS_INTERVAL_MS = 1500L;
+
+ private Handler autoFocusHandler;
+ private int autoFocusMessage;
+
+ void setHandler(Handler autoFocusHandler, int autoFocusMessage) {
+ this.autoFocusHandler = autoFocusHandler;
+ this.autoFocusMessage = autoFocusMessage;
+ }
+
+ public void onAutoFocus(boolean success, Camera camera) {
+ if (autoFocusHandler != null) {
+ Message message = autoFocusHandler.obtainMessage(autoFocusMessage, success);
+ // Simulate continuous autofocus by sending a focus request every
+ // AUTOFOCUS_INTERVAL_MS milliseconds.
+ //Log.d(TAG, "Got auto-focus callback; requesting another");
+ autoFocusHandler.sendMessageDelayed(message, AUTOFOCUS_INTERVAL_MS);
+ autoFocusHandler = null;
+ } else {
+ Log.d(TAG, "Got auto-focus callback, but no handler for it");
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan.camera;
+
+import java.util.Collection;
+
+import org.evergreen.android.barcodescan.PreferencesActivity;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.Point;
+import android.hardware.Camera;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.Display;
+import android.view.WindowManager;
+
+/**
+ * A class which deals with reading, parsing, and setting the camera parameters which are used to
+ * configure the camera hardware.
+ */
+final class CameraConfigurationManager {
+
+ private static final String TAG = "CameraConfiguration";
+ private static final int MIN_PREVIEW_PIXELS = 320 * 240; // small screen
+ private static final int MAX_PREVIEW_PIXELS = 800 * 480; // large/HD screen
+
+ private final Context context;
+ private Point screenResolution;
+ private Point cameraResolution;
+
+ CameraConfigurationManager(Context context) {
+ this.context = context;
+ }
+
+ /**
+ * Reads, one time, values from the camera that are needed by the app.
+ */
+ void initFromCameraParameters(Camera camera) {
+ Camera.Parameters parameters = camera.getParameters();
+ WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ Display display = manager.getDefaultDisplay();
+ int width = display.getWidth();
+ int height = display.getHeight();
+ // We're landscape-only, and have apparently seen issues with display thinking it's portrait
+ // when waking from sleep. If it's not landscape, assume it's mistaken and reverse them:
+ if (width < height) {
+ Log.i(TAG, "Display reports portrait orientation; assuming this is incorrect");
+ int temp = width;
+ width = height;
+ height = temp;
+ }
+ screenResolution = new Point(width, height);
+ Log.i(TAG, "Screen resolution: " + screenResolution);
+ cameraResolution = findBestPreviewSizeValue(parameters, screenResolution, false);
+ Log.i(TAG, "Camera resolution: " + cameraResolution);
+ }
+
+ void setDesiredCameraParameters(Camera camera) {
+ Camera.Parameters parameters = camera.getParameters();
+
+ if (parameters == null) {
+ Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration.");
+ return;
+ }
+
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+
+ initializeTorch(parameters, prefs);
+ String focusMode = findSettableValue(parameters.getSupportedFocusModes(),
+ Camera.Parameters.FOCUS_MODE_AUTO,
+ Camera.Parameters.FOCUS_MODE_MACRO);
+ if (focusMode != null) {
+ parameters.setFocusMode(focusMode);
+ }
+
+ parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
+ camera.setParameters(parameters);
+ }
+
+ Point getCameraResolution() {
+ return cameraResolution;
+ }
+
+ Point getScreenResolution() {
+ return screenResolution;
+ }
+
+ void setTorch(Camera camera, boolean newSetting) {
+ Camera.Parameters parameters = camera.getParameters();
+ doSetTorch(parameters, newSetting);
+ camera.setParameters(parameters);
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ boolean currentSetting = prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false);
+ if (currentSetting != newSetting) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(PreferencesActivity.KEY_FRONT_LIGHT, newSetting);
+ editor.commit();
+ }
+ }
+
+ private static void initializeTorch(Camera.Parameters parameters, SharedPreferences prefs) {
+ boolean currentSetting = prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false);
+ doSetTorch(parameters, currentSetting);
+ }
+
+ private static void doSetTorch(Camera.Parameters parameters, boolean newSetting) {
+ String flashMode;
+ if (newSetting) {
+ flashMode = findSettableValue(parameters.getSupportedFlashModes(),
+ Camera.Parameters.FLASH_MODE_TORCH,
+ Camera.Parameters.FLASH_MODE_ON);
+ } else {
+ flashMode = findSettableValue(parameters.getSupportedFlashModes(),
+ Camera.Parameters.FLASH_MODE_OFF);
+ }
+ if (flashMode != null) {
+ parameters.setFlashMode(flashMode);
+ }
+ }
+
+ private static Point findBestPreviewSizeValue(Camera.Parameters parameters,
+ Point screenResolution,
+ boolean portrait) {
+ Point bestSize = null;
+ int diff = Integer.MAX_VALUE;
+ for (Camera.Size supportedPreviewSize : parameters.getSupportedPreviewSizes()) {
+ int pixels = supportedPreviewSize.height * supportedPreviewSize.width;
+ if (pixels < MIN_PREVIEW_PIXELS || pixels > MAX_PREVIEW_PIXELS) {
+ continue;
+ }
+ int supportedWidth = portrait ? supportedPreviewSize.height : supportedPreviewSize.width;
+ int supportedHeight = portrait ? supportedPreviewSize.width : supportedPreviewSize.height;
+ int newDiff = Math.abs(screenResolution.x * supportedHeight - supportedWidth * screenResolution.y);
+ if (newDiff == 0) {
+ bestSize = new Point(supportedWidth, supportedHeight);
+ break;
+ }
+ if (newDiff < diff) {
+ bestSize = new Point(supportedWidth, supportedHeight);
+ diff = newDiff;
+ }
+ }
+ if (bestSize == null) {
+ Camera.Size defaultSize = parameters.getPreviewSize();
+ bestSize = new Point(defaultSize.width, defaultSize.height);
+ }
+ return bestSize;
+ }
+
+ private static String findSettableValue(Collection<String> supportedValues,
+ String... desiredValues) {
+ Log.i(TAG, "Supported values: " + supportedValues);
+ String result = null;
+ if (supportedValues != null) {
+ for (String desiredValue : desiredValues) {
+ if (supportedValues.contains(desiredValue)) {
+ result = desiredValue;
+ break;
+ }
+ }
+ }
+ Log.i(TAG, "Settable value: " + result);
+ return result;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan.camera;
+
+import java.io.IOException;
+
+import org.evergreen.android.barcodescan.PlanarYUVLuminanceSource;
+import org.evergreen.android.barcodescan.PreferencesActivity;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.Camera;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+/**
+ * This object wraps the Camera service object and expects to be the only one talking to it. The
+ * implementation encapsulates the steps needed to take preview-sized images, which are used for
+ * both preview and decoding.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class CameraManager {
+
+ private static final String TAG = CameraManager.class.getSimpleName();
+
+ private static final int MIN_FRAME_WIDTH = 240;
+ private static final int MIN_FRAME_HEIGHT = 240;
+ private static final int MAX_FRAME_WIDTH = 600;
+ private static final int MAX_FRAME_HEIGHT = 400;
+
+ private final Context context;
+ private final CameraConfigurationManager configManager;
+ private Camera camera;
+ private Rect framingRect;
+ private Rect framingRectInPreview;
+ private boolean initialized;
+ private boolean previewing;
+ private boolean reverseImage;
+ private int requestedFramingRectWidth;
+ private int requestedFramingRectHeight;
+ /**
+ * Preview frames are delivered here, which we pass on to the registered handler. Make sure to
+ * clear the handler so it will only receive one message.
+ */
+ private final PreviewCallback previewCallback;
+ /** Autofocus callbacks arrive here, and are dispatched to the Handler which requested them. */
+ private final AutoFocusCallback autoFocusCallback;
+
+ public CameraManager(Context context) {
+ this.context = context;
+ this.configManager = new CameraConfigurationManager(context);
+ previewCallback = new PreviewCallback(configManager);
+ autoFocusCallback = new AutoFocusCallback();
+ }
+
+ /**
+ * Opens the camera driver and initializes the hardware parameters.
+ *
+ * @param holder The surface object which the camera will draw preview frames into.
+ * @throws IOException Indicates the camera driver failed to open.
+ */
+ public void openDriver(SurfaceHolder holder) throws IOException {
+ Camera theCamera = camera;
+ if (theCamera == null) {
+ theCamera = Camera.open();
+ if (theCamera == null) {
+ throw new IOException();
+ }
+ camera = theCamera;
+ }
+ theCamera.setPreviewDisplay(holder);
+
+ if (!initialized) {
+ initialized = true;
+ configManager.initFromCameraParameters(theCamera);
+ if (requestedFramingRectWidth > 0 && requestedFramingRectHeight > 0) {
+ setManualFramingRect(requestedFramingRectWidth, requestedFramingRectHeight);
+ requestedFramingRectWidth = 0;
+ requestedFramingRectHeight = 0;
+ }
+ }
+ configManager.setDesiredCameraParameters(theCamera);
+
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ reverseImage = prefs.getBoolean(PreferencesActivity.KEY_REVERSE_IMAGE, false);
+ }
+
+ /**
+ * Closes the camera driver if still in use.
+ */
+ public void closeDriver() {
+ if (camera != null) {
+ camera.release();
+ camera = null;
+ // Make sure to clear these each time we close the camera, so that any scanning rect
+ // requested by intent is forgotten.
+ framingRect = null;
+ framingRectInPreview = null;
+ }
+ }
+
+ /**
+ * Asks the camera hardware to begin drawing preview frames to the screen.
+ */
+ public void startPreview() {
+ Camera theCamera = camera;
+ if (theCamera != null && !previewing) {
+ theCamera.startPreview();
+ previewing = true;
+ }
+ }
+
+ /**
+ * Tells the camera to stop drawing preview frames.
+ */
+ public void stopPreview() {
+ if (camera != null && previewing) {
+ camera.stopPreview();
+ previewCallback.setHandler(null, 0);
+ autoFocusCallback.setHandler(null, 0);
+ previewing = false;
+ }
+ }
+
+ /**
+ * A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
+ * in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
+ * respectively.
+ *
+ * @param handler The handler to send the message to.
+ * @param message The what field of the message to be sent.
+ */
+ public void requestPreviewFrame(Handler handler, int message) {
+ Camera theCamera = camera;
+ if (theCamera != null && previewing) {
+ previewCallback.setHandler(handler, message);
+ theCamera.setOneShotPreviewCallback(previewCallback);
+ }
+ }
+
+ /**
+ * Asks the camera hardware to perform an autofocus.
+ *
+ * @param handler The Handler to notify when the autofocus completes.
+ * @param message The message to deliver.
+ */
+ public void requestAutoFocus(Handler handler, int message) {
+ if (camera != null && previewing) {
+ autoFocusCallback.setHandler(handler, message);
+ try {
+ camera.autoFocus(autoFocusCallback);
+ } catch (RuntimeException re) {
+ // Have heard RuntimeException reported in Android 4.0.x+; continue?
+ Log.w(TAG, "Unexpected exception while focusing", re);
+ }
+ }
+ }
+
+ /**
+ * Calculates the framing rect which the UI should draw to show the user where to place the
+ * barcode. This target helps with alignment as well as forces the user to hold the device
+ * far enough away to ensure the image will be in focus.
+ *
+ * @return The rectangle to draw on screen in window coordinates.
+ */
+ public Rect getFramingRect() {
+ if (framingRect == null) {
+ if (camera == null) {
+ return null;
+ }
+ Point screenResolution = configManager.getScreenResolution();
+ int width = screenResolution.x * 3 / 4;
+ if (width < MIN_FRAME_WIDTH) {
+ width = MIN_FRAME_WIDTH;
+ } else if (width > MAX_FRAME_WIDTH) {
+ width = MAX_FRAME_WIDTH;
+ }
+ int height = screenResolution.y * 3 / 4;
+ if (height < MIN_FRAME_HEIGHT) {
+ height = MIN_FRAME_HEIGHT;
+ } else if (height > MAX_FRAME_HEIGHT) {
+ height = MAX_FRAME_HEIGHT;
+ }
+ int leftOffset = (screenResolution.x - width) / 2;
+ int topOffset = (screenResolution.y - height) / 2;
+ framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
+ Log.d(TAG, "Calculated framing rect: " + framingRect);
+ }
+ return framingRect;
+ }
+
+ /**
+ * Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
+ * not UI / screen.
+ */
+ public Rect getFramingRectInPreview() {
+ if (framingRectInPreview == null) {
+ Rect framingRect = getFramingRect();
+ if (framingRect == null) {
+ return null;
+ }
+ Rect rect = new Rect(framingRect);
+ Point cameraResolution = configManager.getCameraResolution();
+ Point screenResolution = configManager.getScreenResolution();
+ rect.left = rect.left * cameraResolution.x / screenResolution.x;
+ rect.right = rect.right * cameraResolution.x / screenResolution.x;
+ rect.top = rect.top * cameraResolution.y / screenResolution.y;
+ rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
+ framingRectInPreview = rect;
+ }
+ return framingRectInPreview;
+ }
+
+ /**
+ * Allows third party apps to specify the scanning rectangle dimensions, rather than determine
+ * them automatically based on screen resolution.
+ *
+ * @param width The width in pixels to scan.
+ * @param height The height in pixels to scan.
+ */
+ public void setManualFramingRect(int width, int height) {
+ if (initialized) {
+ Point screenResolution = configManager.getScreenResolution();
+ if (width > screenResolution.x) {
+ width = screenResolution.x;
+ }
+ if (height > screenResolution.y) {
+ height = screenResolution.y;
+ }
+ int leftOffset = (screenResolution.x - width) / 2;
+ int topOffset = (screenResolution.y - height) / 2;
+ framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
+ Log.d(TAG, "Calculated manual framing rect: " + framingRect);
+ framingRectInPreview = null;
+ } else {
+ requestedFramingRectWidth = width;
+ requestedFramingRectHeight = height;
+ }
+ }
+
+ /**
+ * A factory method to build the appropriate LuminanceSource object based on the format
+ * of the preview buffers, as described by Camera.Parameters.
+ *
+ * @param data A preview frame.
+ * @param width The width of the image.
+ * @param height The height of the image.
+ * @return A PlanarYUVLuminanceSource instance.
+ */
+ public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
+ Rect rect = getFramingRectInPreview();
+ if (rect == null) {
+ return null;
+ }
+ // Go ahead and assume it's YUV rather than die.
+ return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
+ rect.width(), rect.height(), reverseImage);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan.camera;
+
+import android.os.IBinder;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * This class is used to activate the weak light on some camera phones (not flash)
+ * in order to illuminate surfaces for scanning. There is no official way to do this,
+ * but, classes which allow access to this function still exist on some devices.
+ * This therefore proceeds through a great deal of reflection.
+ *
+ * See http://almondmendoza.com/2009/01/05/changing-the-screen-brightness-programatically/ and
+ * http://code.google.com/p/droidled/source/browse/trunk/src/com/droidled/demo/DroidLED.java .
+ * Thanks to Ryan Alford for pointing out the availability of this class.
+ */
+final class FlashlightManager {
+
+ private static final String TAG = FlashlightManager.class.getSimpleName();
+
+ private static final Object iHardwareService;
+ private static final Method setFlashEnabledMethod;
+ static {
+ iHardwareService = getHardwareService();
+ setFlashEnabledMethod = getSetFlashEnabledMethod(iHardwareService);
+ if (iHardwareService == null) {
+ Log.v(TAG, "This device does supports control of a flashlight");
+ } else {
+ Log.v(TAG, "This device does not support control of a flashlight");
+ }
+ }
+
+ private FlashlightManager() {
+ }
+
+ private static Object getHardwareService() {
+ Class<?> serviceManagerClass = maybeForName("android.os.ServiceManager");
+ if (serviceManagerClass == null) {
+ return null;
+ }
+
+ Method getServiceMethod = maybeGetMethod(serviceManagerClass, "getService", String.class);
+ if (getServiceMethod == null) {
+ return null;
+ }
+
+ Object hardwareService = invoke(getServiceMethod, null, "hardware");
+ if (hardwareService == null) {
+ return null;
+ }
+
+ Class<?> iHardwareServiceStubClass = maybeForName("android.os.IHardwareService$Stub");
+ if (iHardwareServiceStubClass == null) {
+ return null;
+ }
+
+ Method asInterfaceMethod = maybeGetMethod(iHardwareServiceStubClass, "asInterface",
+ IBinder.class);
+ if (asInterfaceMethod == null) {
+ return null;
+ }
+
+ return invoke(asInterfaceMethod, null, hardwareService);
+ }
+
+ private static Method getSetFlashEnabledMethod(Object iHardwareService) {
+ if (iHardwareService == null) {
+ return null;
+ }
+ Class<?> proxyClass = iHardwareService.getClass();
+ return maybeGetMethod(proxyClass, "setFlashlightEnabled", boolean.class);
+ }
+
+ private static Class<?> maybeForName(String name) {
+ try {
+ return Class.forName(name);
+ } catch (ClassNotFoundException cnfe) {
+ // OK
+ return null;
+ } catch (RuntimeException re) {
+ Log.w(TAG, "Unexpected error while finding class " + name, re);
+ return null;
+ }
+ }
+
+ private static Method maybeGetMethod(Class<?> clazz, String name, Class<?>... argClasses) {
+ try {
+ return clazz.getMethod(name, argClasses);
+ } catch (NoSuchMethodException nsme) {
+ // OK
+ return null;
+ } catch (RuntimeException re) {
+ Log.w(TAG, "Unexpected error while finding method " + name, re);
+ return null;
+ }
+ }
+
+ private static Object invoke(Method method, Object instance, Object... args) {
+ try {
+ return method.invoke(instance, args);
+ } catch (IllegalAccessException e) {
+ Log.w(TAG, "Unexpected error while invoking " + method, e);
+ return null;
+ } catch (InvocationTargetException e) {
+ Log.w(TAG, "Unexpected error while invoking " + method, e.getCause());
+ return null;
+ } catch (RuntimeException re) {
+ Log.w(TAG, "Unexpected error while invoking " + method, re);
+ return null;
+ }
+ }
+
+ static void enableFlashlight() {
+ setFlashlight(true);
+ }
+
+ static void disableFlashlight() {
+ setFlashlight(false);
+ }
+
+ private static void setFlashlight(boolean active) {
+ if (iHardwareService != null) {
+ invoke(setFlashEnabledMethod, iHardwareService, active);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan.camera;
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * 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.
+ */
+
+import android.graphics.Point;
+import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+final class PreviewCallback implements Camera.PreviewCallback {
+
+ private static final String TAG = PreviewCallback.class.getSimpleName();
+
+ private final CameraConfigurationManager configManager;
+ private Handler previewHandler;
+ private int previewMessage;
+
+ PreviewCallback(CameraConfigurationManager configManager) {
+ this.configManager = configManager;
+ }
+
+ void setHandler(Handler previewHandler, int previewMessage) {
+ this.previewHandler = previewHandler;
+ this.previewMessage = previewMessage;
+ }
+
+ @Override
+ public void onPreviewFrame(byte[] data, Camera camera) {
+ Point cameraResolution = configManager.getCameraResolution();
+ Handler thePreviewHandler = previewHandler;
+ if (thePreviewHandler != null) {
+ Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
+ cameraResolution.y, data);
+ message.sendToTarget();
+ previewHandler = null;
+ } else {
+ Log.d(TAG, "Got preview callback, but no handler for it");
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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 org.evergreen.android.barcodescan.result;
+
+import com.google.zxing.Result;
+import com.google.zxing.client.result.ParsedResult;
+import com.google.zxing.client.result.ResultParser;
+
+import android.app.Activity;
+
+/**
+ * A base class for the Android-specific barcode handlers. These allow the app to polymorphically
+ * suggest the appropriate actions for each data type.
+ *
+ * This class also contains a bunch of utility methods to take common actions like opening a URL.
+ * They could easily be moved into a helper object, but it can't be static because the Activity
+ * instance is needed to launch an intent.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public class ResultHandler {
+
+ private final ParsedResult result;
+ private final Activity activity;
+ private final Result rawResult;
+
+ public ResultHandler(Activity activity, Result rawResult) {
+ this.activity = activity;
+ this.rawResult = rawResult;
+ result = parseResult(rawResult);
+ }
+
+
+ public ParsedResult getResult() {
+ return result;
+ }
+
+ private static ParsedResult parseResult(Result rawResult) {
+ return ResultParser.parseResult(rawResult);
+ }
+
+ /**
+ * Create a possibly styled string for the contents of the current barcode.
+ *
+ * @return The text to be displayed.
+ */
+ public CharSequence getDisplayContents() {
+ String contents = result.getDisplayResult();
+ return contents.replace("\r", "");
+ }
+}
import org.evergreen.android.accountAccess.SessionNotFoundException;
import org.evergreen.android.accountAccess.bookbags.BookBag;
import org.evergreen.android.accountAccess.holds.PlaceHold;
+import org.evergreen.android.barcodescan.CaptureActivity;
import org.evergreen.android.globals.GlobalConfigs;
import org.evergreen.android.globals.NoAccessToServer;
import org.evergreen.android.globals.NoNetworkAccessException;
});
barcodeScanButton = (ImageButton) findViewById(R.id.barcode_scan_button);
-
+ barcodeScanButton.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ Intent barcodeScan = new Intent(getApplicationContext(), CaptureActivity.class);
+ startActivityForResult(barcodeScan, 10);
+ }
+ });
//singleton initialize necessary IDL and Org data
globalConfigs = GlobalConfigs.getGlobalConfigs(this);