[SCM] Multi-format 1D/2D barcode image processing library branch, upstream, updated. 24d4480bc48cf9eabf7b2bd2f528248b0e458809
srowen
srowen at 59b500cc-1b3d-0410-9834-0bbf25fbcc57
Wed Aug 4 01:30:56 UTC 2010
The following commit has been merged in the upstream branch:
commit 4b3bfd8a8f16dad6a1413f75e68a5776e9e308b7
Author: srowen <srowen at 59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Date: Wed Apr 7 18:03:14 2010 +0000
Issue 376: re-set camera params after first auto-focus callback to make it work on Droid. Along the way, did a very big reorganization of CameraManager since it was becoming spaghetti code
git-svn-id: http://zxing.googlecode.com/svn/trunk@1292 59b500cc-1b3d-0410-9834-0bbf25fbcc57
diff --git a/android/src/com/google/zxing/client/android/CameraManager.java b/android/src/com/google/zxing/client/android/CameraManager.java
deleted file mode 100755
index c18fc6d..0000000
--- a/android/src/com/google/zxing/client/android/CameraManager.java
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * 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 com.google.zxing.client.android;
-
-import com.google.zxing.ResultPoint;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.hardware.Camera;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Message;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import android.view.Display;
-import android.view.SurfaceHolder;
-import android.view.WindowManager;
-
-import java.io.IOException;
-import java.util.regex.Pattern;
-
-/**
- * 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 at google.com (Daniel Switkin)
- */
-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 = 480;
- private static final int MAX_FRAME_HEIGHT = 360;
-
- private static final int TEN_DESIRED_ZOOM = 27;
- private static final int DESIRED_SHARPNESS = 30;
-
- private static final Pattern COMMA_PATTERN = Pattern.compile(",");
-
- private static CameraManager cameraManager;
-
- private Camera camera;
- private final Context context;
- private Point screenResolution;
- private Point cameraResolution;
- private Rect framingRect;
- private Handler previewHandler;
- private int previewMessage;
- private Handler autoFocusHandler;
- private int autoFocusMessage;
- private boolean initialized;
- private boolean previewing;
- private int previewFormat;
- private String previewFormatString;
- private final boolean useOneShotPreviewCallback;
-
- /**
- * 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 Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
- public void onPreviewFrame(byte[] data, Camera camera) {
- if (!useOneShotPreviewCallback) {
- camera.setPreviewCallback(null);
- }
- if (previewHandler != null) {
- Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x,
- cameraResolution.y, data);
- message.sendToTarget();
- previewHandler = null;
- }
- }
- };
-
- /**
- * Autofocus callbacks arrive here, and are dispatched to the Handler which requested them.
- */
- private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
- 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 1.5 seconds.
- autoFocusHandler.sendMessageDelayed(message, 1500L);
- autoFocusHandler = null;
- }
- }
- };
-
- /**
- * Initializes this static object with the Context of the calling Activity.
- *
- * @param context The Activity which wants to use the camera.
- */
- public static void init(Context context) {
- if (cameraManager == null) {
- cameraManager = new CameraManager(context);
- }
- }
-
- /**
- * Gets the CameraManager singleton instance.
- *
- * @return A reference to the CameraManager singleton.
- */
- public static CameraManager get() {
- return cameraManager;
- }
-
- private CameraManager(Context context) {
- this.context = context;
- camera = null;
- initialized = false;
- previewing = false;
-
- // Camera.setOneShotPreviewCallback() has a race condition in Cupcake, so we use the older
- // Camera.setPreviewCallback() on 1.5 and earlier. For Donut and later, we need to use
- // the more efficient one shot callback, as the older one can swamp the system and cause it
- // to run out of memory. We can't use SDK_INT because it was introduced in the Donut SDK.
- useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > Build.VERSION_CODES.CUPCAKE;
- }
-
- /**
- * 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 {
- if (camera == null) {
- camera = Camera.open();
- if (camera == null) {
- throw new IOException();
- }
- camera.setPreviewDisplay(holder);
-
- if (!initialized) {
- initialized = true;
- getScreenResolution();
- }
-
- setCameraParameters();
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- if (prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false)) {
- FlashlightManager.enableFlashlight();
- }
- }
- }
-
- /**
- * Closes the camera driver if still in use.
- */
- public void closeDriver() {
- if (camera != null) {
- FlashlightManager.disableFlashlight();
- camera.release();
- camera = null;
- }
- }
-
- /**
- * Asks the camera hardware to begin drawing preview frames to the screen.
- */
- public void startPreview() {
- if (camera != null && !previewing) {
- camera.startPreview();
- previewing = true;
- }
- }
-
- /**
- * Tells the camera to stop drawing preview frames.
- */
- public void stopPreview() {
- if (camera != null && previewing) {
- if (!useOneShotPreviewCallback) {
- camera.setPreviewCallback(null);
- }
- camera.stopPreview();
- previewHandler = null;
- autoFocusHandler = null;
- 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) {
- if (camera != null && previewing) {
- previewHandler = handler;
- previewMessage = message;
- if (useOneShotPreviewCallback) {
- camera.setOneShotPreviewCallback(previewCallback);
- } else {
- camera.setPreviewCallback(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) {
- autoFocusHandler = handler;
- autoFocusMessage = message;
- camera.autoFocus(autoFocusCallback);
- }
- }
-
- /**
- * 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;
- }
- int width = cameraResolution.x * 3 / 4;
- if (width < MIN_FRAME_WIDTH) {
- width = MIN_FRAME_WIDTH;
- } else if (width > MAX_FRAME_WIDTH) {
- width = MAX_FRAME_WIDTH;
- }
- int height = cameraResolution.y * 3 / 4;
- if (height < MIN_FRAME_HEIGHT) {
- height = MIN_FRAME_HEIGHT;
- } else if (height > MAX_FRAME_HEIGHT) {
- height = MAX_FRAME_HEIGHT;
- }
- int leftOffset = (cameraResolution.x - width) / 2;
- int topOffset = (cameraResolution.y - height) / 2;
- framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
- Log.v(TAG, "Calculated framing rect: " + framingRect);
- }
- return framingRect;
- }
-
- /**
- * Converts the result points from still resolution coordinates to screen coordinates.
- *
- * @param points The points returned by the Reader subclass through Result.getResultPoints().
- * @return An array of Points scaled to the size of the framing rect and offset appropriately
- * so they can be drawn in screen coordinates.
- */
- public Point[] convertResultPoints(ResultPoint[] points) {
- Rect frame = getFramingRect();
- int count = points.length;
- Point[] output = new Point[count];
- for (int x = 0; x < count; x++) {
- output[x] = new Point();
- output[x].x = frame.left + (int) (points[x].getX() + 0.5f);
- output[x].y = frame.top + (int) (points[x].getY() + 0.5f);
- }
- return output;
- }
-
- /**
- * 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 = getFramingRect();
- switch (previewFormat) {
- // This is the standard Android format which all devices are REQUIRED to support.
- // In theory, it's the only one we should ever care about.
- case PixelFormat.YCbCr_420_SP:
- // This format has never been seen in the wild, but is compatible as we only care
- // about the Y channel, so allow it.
- case PixelFormat.YCbCr_422_SP:
- return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
- rect.width(), rect.height());
- default:
- // The Samsung Moment incorrectly uses this variant instead of the 'sp' version.
- // Fortunately, it too has all the Y data up front, so we can read it.
- if ("yuv420p".equals(previewFormatString)) {
- return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
- rect.width(), rect.height());
- }
- }
- throw new IllegalArgumentException("Unsupported picture format: " +
- previewFormat + '/' + previewFormatString);
- }
-
- /**
- * Sets the camera up to take preview images which are used for both preview and decoding.
- * We detect the preview format here so that buildLuminanceSource() can build an appropriate
- * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
- * and the planar Y can be used for barcode scanning without a copy in some cases.
- */
- private void setCameraParameters() {
- Camera.Parameters parameters = camera.getParameters();
- previewFormat = parameters.getPreviewFormat();
- previewFormatString = parameters.get("preview-format");
- Log.v(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString);
-
- cameraResolution = getCameraResolution(parameters);
- Log.v(TAG, "Setting preview size: " + cameraResolution.x + ", " + cameraResolution.y);
- parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
-
- setFlash(parameters);
- setZoom(parameters);
- //setSharpness(parameters);
-
- camera.setParameters(parameters);
- }
-
- private Point getScreenResolution() {
- if (screenResolution == null) {
- WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- Display display = manager.getDefaultDisplay();
- screenResolution = new Point(display.getWidth(), display.getHeight());
- }
- return screenResolution;
- }
-
- private Point getCameraResolution(Camera.Parameters parameters) {
-
- String previewSizeValueString = parameters.get("preview-size-values");
- // saw this on Xperia
- if (previewSizeValueString == null) {
- previewSizeValueString = parameters.get("preview-size-value");
- }
-
- Point cameraResolution = null;
-
- if (previewSizeValueString != null) {
- Log.v(TAG, "preview-size parameter: " + previewSizeValueString);
- cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
- }
-
- if (cameraResolution == null) {
- // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
- cameraResolution = new Point(
- (screenResolution.x >> 3) << 3,
- (screenResolution.y >> 3) << 3);
- }
-
- return cameraResolution;
- }
-
- private static Point findBestPreviewSizeValue(String previewSizeValueString, Point screenResolution) {
- int bestX = 0;
- int bestY = 0;
- int diff = Integer.MAX_VALUE;
- for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {
-
- previewSize = previewSize.trim();
- int dimPosition = previewSize.indexOf('x');
- if (dimPosition < 0) {
- Log.w(TAG, "Bad preview-size: " + previewSize);
- continue;
- }
-
- int newX;
- int newY;
- try {
- newX = Integer.parseInt(previewSize.substring(0, dimPosition));
- newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
- } catch (NumberFormatException nfe) {
- Log.w(TAG, "Bad preview-size: " + previewSize);
- continue;
- }
-
- int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
- if (newDiff == 0) {
- bestX = newX;
- bestY = newY;
- break;
- } else if (newDiff < diff) {
- bestX = newX;
- bestY = newY;
- diff = newDiff;
- }
-
- }
-
- if (bestX > 0 && bestY > 0) {
- return new Point(bestX, bestY);
- }
- return null;
- }
-
- private static int findBestMotZoomValue(String stringValues, int tenDesiredZoom) {
- int tenBestValue = 0;
- for (String stringValue : COMMA_PATTERN.split(stringValues)) {
- stringValue = stringValue.trim();
- double value;
- try {
- value = Double.parseDouble(stringValue);
- } catch (NumberFormatException nfe) {
- return tenDesiredZoom;
- }
- int tenValue = (int) (10.0 * value);
- if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) {
- tenBestValue = tenValue;
- }
- }
- return tenBestValue;
- }
-
- private void setFlash(Camera.Parameters parameters) {
- // FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
- parameters.set("flash-value", 2);
- // This is the standard setting to turn the flash off that all devices should honor.
- parameters.set("flash-mode", "off");
- }
-
- private void setZoom(Camera.Parameters parameters) {
-
- String zoomSupportedString = parameters.get("zoom-supported");
- if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
- return;
- }
-
- int tenDesiredZoom = TEN_DESIRED_ZOOM;
-
- String maxZoomString = parameters.get("max-zoom");
- if (maxZoomString != null) {
- try {
- int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
- if (tenDesiredZoom > tenMaxZoom) {
- tenDesiredZoom = tenMaxZoom;
- }
- } catch (NumberFormatException nfe) {
- Log.w(TAG, "Bad max-zoom: " + maxZoomString);
- }
- }
-
- String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
- if (takingPictureZoomMaxString != null) {
- try {
- int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
- if (tenDesiredZoom > tenMaxZoom) {
- tenDesiredZoom = tenMaxZoom;
- }
- } catch (NumberFormatException nfe) {
- Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString);
- }
- }
-
- String motZoomValuesString = parameters.get("mot-zoom-values");
- if (motZoomValuesString != null) {
- tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
- }
-
- String motZoomStepString = parameters.get("mot-zoom-step");
- if (motZoomStepString != null) {
- try {
- double motZoomStep = Double.parseDouble(motZoomStepString.trim());
- int tenZoomStep = (int) (10.0 * motZoomStep);
- if (tenZoomStep > 1) {
- tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
- }
- } catch (NumberFormatException nfe) {
- // continue
- }
- }
-
- // Set zoom. This helps encourage the user to pull back.
- // Some devices like the Behold have a zoom parameter
- if (maxZoomString != null || motZoomValuesString != null) {
- parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
- }
-
- // Most devices, like the Hero, appear to expose this zoom parameter.
- // It takes on values like "27" which appears to mean 2.7x zoom
- if (takingPictureZoomMaxString != null) {
- parameters.set("taking-picture-zoom", tenDesiredZoom);
- }
- }
-
- /*
- private void setSharpness(Camera.Parameters parameters) {
-
- int desiredSharpness = DESIRED_SHARPNESS;
-
- String maxSharpnessString = parameters.get("sharpness-max");
- if (maxSharpnessString != null) {
- try {
- int maxSharpness = Integer.parseInt(maxSharpnessString);
- if (desiredSharpness > maxSharpness) {
- desiredSharpness = maxSharpness;
- }
- } catch (NumberFormatException nfe) {
- Log.w(TAG, "Bad sharpness-max: " + maxSharpnessString);
- }
- }
-
- parameters.set("sharpness", desiredSharpness);
- }
- */
-}
diff --git a/android/src/com/google/zxing/client/android/CaptureActivity.java b/android/src/com/google/zxing/client/android/CaptureActivity.java
index ba5ca28..9ad0093 100755
--- a/android/src/com/google/zxing/client/android/CaptureActivity.java
+++ b/android/src/com/google/zxing/client/android/CaptureActivity.java
@@ -19,6 +19,7 @@ package com.google.zxing.client.android;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
+import com.google.zxing.client.android.camera.CameraManager;
import com.google.zxing.client.android.history.HistoryManager;
import com.google.zxing.client.android.result.ResultButtonListener;
import com.google.zxing.client.android.result.ResultHandler;
diff --git a/android/src/com/google/zxing/client/android/CaptureActivityHandler.java b/android/src/com/google/zxing/client/android/CaptureActivityHandler.java
index 362881c..a0d29e6 100755
--- a/android/src/com/google/zxing/client/android/CaptureActivityHandler.java
+++ b/android/src/com/google/zxing/client/android/CaptureActivityHandler.java
@@ -18,6 +18,7 @@ package com.google.zxing.client.android;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
+import com.google.zxing.client.android.camera.CameraManager;
import android.app.Activity;
import android.content.Intent;
@@ -35,6 +36,7 @@ import java.util.Vector;
* @author dswitkin at google.com (Daniel Switkin)
*/
public final class CaptureActivityHandler extends Handler {
+
private final CaptureActivity activity;
private final DecodeThread decodeThread;
private State state;
@@ -122,4 +124,5 @@ public final class CaptureActivityHandler extends Handler {
activity.drawViewfinder();
}
}
+
}
diff --git a/android/src/com/google/zxing/client/android/DecodeThread.java b/android/src/com/google/zxing/client/android/DecodeThread.java
index dce7d14..7a407b1 100755
--- a/android/src/com/google/zxing/client/android/DecodeThread.java
+++ b/android/src/com/google/zxing/client/android/DecodeThread.java
@@ -23,6 +23,7 @@ import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.ResultPointCallback;
+import com.google.zxing.client.android.camera.CameraManager;
import com.google.zxing.common.HybridBinarizer;
import android.content.SharedPreferences;
@@ -141,4 +142,5 @@ final class DecodeThread extends Thread {
message.sendToTarget();
}
}
+
}
diff --git a/android/src/com/google/zxing/client/android/PlanarYUVLuminanceSource.java b/android/src/com/google/zxing/client/android/PlanarYUVLuminanceSource.java
index 549dfd5..31cf7d9 100644
--- a/android/src/com/google/zxing/client/android/PlanarYUVLuminanceSource.java
+++ b/android/src/com/google/zxing/client/android/PlanarYUVLuminanceSource.java
@@ -37,7 +37,7 @@ public final class PlanarYUVLuminanceSource extends LuminanceSource {
private final int left;
private final int top;
- PlanarYUVLuminanceSource(byte[] yuvData, int dataWidth, int dataHeight, int left, int top,
+ public PlanarYUVLuminanceSource(byte[] yuvData, int dataWidth, int dataHeight, int left, int top,
int width, int height) {
super(width, height);
diff --git a/android/src/com/google/zxing/client/android/PreferencesActivity.java b/android/src/com/google/zxing/client/android/PreferencesActivity.java
index 090953a..d34e7ff 100755
--- a/android/src/com/google/zxing/client/android/PreferencesActivity.java
+++ b/android/src/com/google/zxing/client/android/PreferencesActivity.java
@@ -31,16 +31,16 @@ import android.preference.PreferenceScreen;
public final class PreferencesActivity extends PreferenceActivity
implements OnSharedPreferenceChangeListener {
- static final String KEY_DECODE_1D = "preferences_decode_1D";
- static final String KEY_DECODE_QR = "preferences_decode_QR";
+ 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_CUSTOM_PRODUCT_SEARCH = "preferences_custom_product_search";
- static final String KEY_PLAY_BEEP = "preferences_play_beep";
- static final String KEY_VIBRATE = "preferences_vibrate";
- static final String KEY_COPY_TO_CLIPBOARD = "preferences_copy_to_clipboard";
- static final String KEY_FRONT_LIGHT = "preferences_front_light";
+ 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";
- static final String KEY_HELP_VERSION_SHOWN = "preferences_help_version_shown";
+ 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;
diff --git a/android/src/com/google/zxing/client/android/ViewfinderView.java b/android/src/com/google/zxing/client/android/ViewfinderView.java
index b972077..8696062 100755
--- a/android/src/com/google/zxing/client/android/ViewfinderView.java
+++ b/android/src/com/google/zxing/client/android/ViewfinderView.java
@@ -16,6 +16,9 @@
package com.google.zxing.client.android;
+import com.google.zxing.ResultPoint;
+import com.google.zxing.client.android.camera.CameraManager;
+
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -24,7 +27,6 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
-import com.google.zxing.ResultPoint;
import java.util.Collection;
import java.util.HashSet;
@@ -36,6 +38,7 @@ import java.util.HashSet;
* @author dswitkin at 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 = 100L;
private static final int OPAQUE = 0xFF;
diff --git a/android/src/com/google/zxing/client/android/camera/AutoFocusCallback.java b/android/src/com/google/zxing/client/android/camera/AutoFocusCallback.java
new file mode 100644
index 0000000..fb3dd04
--- /dev/null
+++ b/android/src/com/google/zxing/client/android/camera/AutoFocusCallback.java
@@ -0,0 +1,55 @@
+/*
+ * 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 com.google.zxing.client.android.camera;
+
+import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Message;
+
+final class AutoFocusCallback implements Camera.AutoFocusCallback {
+
+ private static final long AUTOFOCUS_INTERVAL_MS = 1500L;
+
+ private final CameraConfigurationManager configManager;
+ private boolean reinitCamera;
+ private Handler autoFocusHandler;
+ private int autoFocusMessage;
+
+ AutoFocusCallback(CameraConfigurationManager configManager) {
+ this.configManager = configManager;
+ }
+
+ 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.
+ autoFocusHandler.sendMessageDelayed(message, AUTOFOCUS_INTERVAL_MS);
+ autoFocusHandler = null;
+ if (!reinitCamera) {
+ reinitCamera = true;
+ configManager.setDesiredCameraParameters(camera);
+ }
+ }
+ }
+
+}
diff --git a/android/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java b/android/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java
new file mode 100644
index 0000000..e70b1a3
--- /dev/null
+++ b/android/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java
@@ -0,0 +1,269 @@
+/*
+ * 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 com.google.zxing.client.android.camera;
+
+import java.util.regex.Pattern;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.hardware.Camera;
+import android.util.Log;
+import android.view.Display;
+import android.view.WindowManager;
+
+final class CameraConfigurationManager {
+
+ private static final String TAG = CameraConfigurationManager.class.getSimpleName();
+
+ private static final int TEN_DESIRED_ZOOM = 27;
+ private static final int DESIRED_SHARPNESS = 30;
+
+ private static final Pattern COMMA_PATTERN = Pattern.compile(",");
+
+ private final Context context;
+ private Point screenResolution;
+ private Point cameraResolution;
+ private int previewFormat;
+ private String previewFormatString;
+
+ 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();
+ previewFormat = parameters.getPreviewFormat();
+ previewFormatString = parameters.get("preview-format");
+ Log.v(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString);
+ screenResolution = getScreenResolution();
+ cameraResolution = getCameraResolution(parameters);
+ }
+
+ /**
+ * Sets the camera up to take preview images which are used for both preview and decoding.
+ * We detect the preview format here so that buildLuminanceSource() can build an appropriate
+ * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
+ * and the planar Y can be used for barcode scanning without a copy in some cases.
+ */
+ void setDesiredCameraParameters(Camera camera) {
+ Camera.Parameters parameters = camera.getParameters();
+ Log.v(TAG, "Setting preview size: " + cameraResolution.x + ", " + cameraResolution.y);
+ parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
+ setFlash(parameters);
+ setZoom(parameters);
+ //setSharpness(parameters);
+ camera.setParameters(parameters);
+ }
+
+ Point getCameraResolution() {
+ return cameraResolution;
+ }
+
+ int getPreviewFormat() {
+ return previewFormat;
+ }
+
+ String getPreviewFormatString() {
+ return previewFormatString;
+ }
+
+ private Point getScreenResolution() {
+ WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ Display display = manager.getDefaultDisplay();
+ return new Point(display.getWidth(), display.getHeight());
+ }
+
+ private Point getCameraResolution(Camera.Parameters parameters) {
+
+ String previewSizeValueString = parameters.get("preview-size-values");
+ // saw this on Xperia
+ if (previewSizeValueString == null) {
+ previewSizeValueString = parameters.get("preview-size-value");
+ }
+
+ Point cameraResolution = null;
+
+ if (previewSizeValueString != null) {
+ Log.v(TAG, "preview-size parameter: " + previewSizeValueString);
+ cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
+ }
+
+ if (cameraResolution == null) {
+ // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
+ cameraResolution = new Point(
+ (screenResolution.x >> 3) << 3,
+ (screenResolution.y >> 3) << 3);
+ }
+
+ return cameraResolution;
+ }
+
+ private static Point findBestPreviewSizeValue(String previewSizeValueString, Point screenResolution) {
+ int bestX = 0;
+ int bestY = 0;
+ int diff = Integer.MAX_VALUE;
+ for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {
+
+ previewSize = previewSize.trim();
+ int dimPosition = previewSize.indexOf('x');
+ if (dimPosition < 0) {
+ Log.w(TAG, "Bad preview-size: " + previewSize);
+ continue;
+ }
+
+ int newX;
+ int newY;
+ try {
+ newX = Integer.parseInt(previewSize.substring(0, dimPosition));
+ newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
+ } catch (NumberFormatException nfe) {
+ Log.w(TAG, "Bad preview-size: " + previewSize);
+ continue;
+ }
+
+ int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
+ if (newDiff == 0) {
+ bestX = newX;
+ bestY = newY;
+ break;
+ } else if (newDiff < diff) {
+ bestX = newX;
+ bestY = newY;
+ diff = newDiff;
+ }
+
+ }
+
+ if (bestX > 0 && bestY > 0) {
+ return new Point(bestX, bestY);
+ }
+ return null;
+ }
+
+ private static int findBestMotZoomValue(String stringValues, int tenDesiredZoom) {
+ int tenBestValue = 0;
+ for (String stringValue : COMMA_PATTERN.split(stringValues)) {
+ stringValue = stringValue.trim();
+ double value;
+ try {
+ value = Double.parseDouble(stringValue);
+ } catch (NumberFormatException nfe) {
+ return tenDesiredZoom;
+ }
+ int tenValue = (int) (10.0 * value);
+ if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) {
+ tenBestValue = tenValue;
+ }
+ }
+ return tenBestValue;
+ }
+
+ private void setFlash(Camera.Parameters parameters) {
+ // FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
+ parameters.set("flash-value", 2);
+ // This is the standard setting to turn the flash off that all devices should honor.
+ parameters.set("flash-mode", "off");
+ }
+
+ private void setZoom(Camera.Parameters parameters) {
+
+ String zoomSupportedString = parameters.get("zoom-supported");
+ if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
+ return;
+ }
+
+ int tenDesiredZoom = TEN_DESIRED_ZOOM;
+
+ String maxZoomString = parameters.get("max-zoom");
+ if (maxZoomString != null) {
+ try {
+ int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
+ if (tenDesiredZoom > tenMaxZoom) {
+ tenDesiredZoom = tenMaxZoom;
+ }
+ } catch (NumberFormatException nfe) {
+ Log.w(TAG, "Bad max-zoom: " + maxZoomString);
+ }
+ }
+
+ String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
+ if (takingPictureZoomMaxString != null) {
+ try {
+ int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
+ if (tenDesiredZoom > tenMaxZoom) {
+ tenDesiredZoom = tenMaxZoom;
+ }
+ } catch (NumberFormatException nfe) {
+ Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString);
+ }
+ }
+
+ String motZoomValuesString = parameters.get("mot-zoom-values");
+ if (motZoomValuesString != null) {
+ tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
+ }
+
+ String motZoomStepString = parameters.get("mot-zoom-step");
+ if (motZoomStepString != null) {
+ try {
+ double motZoomStep = Double.parseDouble(motZoomStepString.trim());
+ int tenZoomStep = (int) (10.0 * motZoomStep);
+ if (tenZoomStep > 1) {
+ tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
+ }
+ } catch (NumberFormatException nfe) {
+ // continue
+ }
+ }
+
+ // Set zoom. This helps encourage the user to pull back.
+ // Some devices like the Behold have a zoom parameter
+ if (maxZoomString != null || motZoomValuesString != null) {
+ parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
+ }
+
+ // Most devices, like the Hero, appear to expose this zoom parameter.
+ // It takes on values like "27" which appears to mean 2.7x zoom
+ if (takingPictureZoomMaxString != null) {
+ parameters.set("taking-picture-zoom", tenDesiredZoom);
+ }
+ }
+
+ /*
+ private void setSharpness(Camera.Parameters parameters) {
+
+ int desiredSharpness = DESIRED_SHARPNESS;
+
+ String maxSharpnessString = parameters.get("sharpness-max");
+ if (maxSharpnessString != null) {
+ try {
+ int maxSharpness = Integer.parseInt(maxSharpnessString);
+ if (desiredSharpness > maxSharpness) {
+ desiredSharpness = maxSharpness;
+ }
+ } catch (NumberFormatException nfe) {
+ Log.w(TAG, "Bad sharpness-max: " + maxSharpnessString);
+ }
+ }
+
+ parameters.set("sharpness", desiredSharpness);
+ }
+ */
+}
diff --git a/androidtest/src/com/google/zxing/client/androidtest/CameraManager.java b/android/src/com/google/zxing/client/android/camera/CameraManager.java
similarity index 55%
copy from androidtest/src/com/google/zxing/client/androidtest/CameraManager.java
copy to android/src/com/google/zxing/client/android/camera/CameraManager.java
index 0df0f7a..5f67471 100755
--- a/androidtest/src/com/google/zxing/client/androidtest/CameraManager.java
+++ b/android/src/com/google/zxing/client/android/camera/CameraManager.java
@@ -14,19 +14,23 @@
* limitations under the License.
*/
-package com.google.zxing.client.androidtest;
+package com.google.zxing.client.android.camera;
+
+import com.google.zxing.ResultPoint;
import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Build;
import android.os.Handler;
-import android.os.Message;
+import android.preference.PreferenceManager;
import android.util.Log;
-import android.view.Display;
import android.view.SurfaceHolder;
-import android.view.WindowManager;
+import com.google.zxing.client.android.PlanarYUVLuminanceSource;
+import com.google.zxing.client.android.PreferencesActivity;
import java.io.IOException;
@@ -37,61 +41,31 @@ import java.io.IOException;
*
* @author dswitkin at google.com (Daniel Switkin)
*/
-final class CameraManager {
- private static final String TAG = "CameraManager";
+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 = 480;
private static final int MAX_FRAME_HEIGHT = 360;
private static CameraManager cameraManager;
- private Camera camera;
+
private final Context context;
- private Point screenResolution;
- private Point cameraResolution;
+ private final CameraConfigurationManager configManager;
+ private Camera camera;
private Rect framingRect;
- private Handler previewHandler;
- private int previewMessage;
- private Handler autoFocusHandler;
- private int autoFocusMessage;
private boolean initialized;
private boolean previewing;
- private int previewFormat;
- private String previewFormatString;
- private boolean useOneShotPreviewCallback;
-
+ private final boolean useOneShotPreviewCallback;
/**
* 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 Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
- public void onPreviewFrame(byte[] data, Camera camera) {
- if (!useOneShotPreviewCallback) {
- camera.setPreviewCallback(null);
- }
- if (previewHandler != null) {
- Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x,
- cameraResolution.y, data);
- message.sendToTarget();
- previewHandler = null;
- }
- }
- };
-
- /**
- * Autofocus callbacks arrive here, and are dispatched to the Handler which requested them.
- */
- private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
- public void onAutoFocus(boolean success, Camera camera) {
- if (autoFocusHandler != null) {
- Message message = autoFocusHandler.obtainMessage(autoFocusMessage, success);
- // Barcode Scanner needs to insert a delay here because it does continuous focus,
- // but this test app does not, so send the message immediately.
- message.sendToTarget();
- autoFocusHandler = null;
- }
- }
- };
+ private final PreviewCallback previewCallback;
+ /** Autofocus callbacks arrive here, and are dispatched to the Handler which requested them. */
+ private final AutoFocusCallback autoFocusCallback;
/**
* Initializes this static object with the Context of the calling Activity.
@@ -114,20 +88,18 @@ final class CameraManager {
}
private CameraManager(Context context) {
+
this.context = context;
- camera = null;
- initialized = false;
- previewing = false;
+ this.configManager = new CameraConfigurationManager(context);
// Camera.setOneShotPreviewCallback() has a race condition in Cupcake, so we use the older
// Camera.setPreviewCallback() on 1.5 and earlier. For Donut and later, we need to use
// the more efficient one shot callback, as the older one can swamp the system and cause it
// to run out of memory. We can't use SDK_INT because it was introduced in the Donut SDK.
- if (Integer.parseInt(Build.VERSION.SDK) <= Build.VERSION_CODES.CUPCAKE) {
- useOneShotPreviewCallback = false;
- } else {
- useOneShotPreviewCallback = true;
- }
+ useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > Build.VERSION_CODES.CUPCAKE;
+
+ previewCallback = new PreviewCallback(configManager, useOneShotPreviewCallback);
+ autoFocusCallback = new AutoFocusCallback(configManager);
}
/**
@@ -136,23 +108,25 @@ final class CameraManager {
* @param holder The surface object which the camera will draw preview frames into.
* @throws IOException Indicates the camera driver failed to open.
*/
- public String openDriver(SurfaceHolder holder, boolean getParameters) throws IOException {
- String result = null;
+ public void openDriver(SurfaceHolder holder) throws IOException {
if (camera == null) {
camera = Camera.open();
+ if (camera == null) {
+ throw new IOException();
+ }
camera.setPreviewDisplay(holder);
if (!initialized) {
initialized = true;
- getScreenResolution();
+ configManager.initFromCameraParameters(camera);
}
+ configManager.setDesiredCameraParameters(camera);
- if (getParameters) {
- result = collectCameraParameters();
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ if (prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false)) {
+ FlashlightManager.enableFlashlight();
}
- setCameraParameters();
}
- return result;
}
/**
@@ -160,6 +134,7 @@ final class CameraManager {
*/
public void closeDriver() {
if (camera != null) {
+ FlashlightManager.disableFlashlight();
camera.release();
camera = null;
}
@@ -184,8 +159,8 @@ final class CameraManager {
camera.setPreviewCallback(null);
}
camera.stopPreview();
- previewHandler = null;
- autoFocusHandler = null;
+ previewCallback.setHandler(null, 0);
+ autoFocusCallback.setHandler(null, 0);
previewing = false;
}
}
@@ -200,8 +175,7 @@ final class CameraManager {
*/
public void requestPreviewFrame(Handler handler, int message) {
if (camera != null && previewing) {
- previewHandler = handler;
- previewMessage = message;
+ previewCallback.setHandler(handler, message);
if (useOneShotPreviewCallback) {
camera.setOneShotPreviewCallback(previewCallback);
} else {
@@ -218,8 +192,7 @@ final class CameraManager {
*/
public void requestAutoFocus(Handler handler, int message) {
if (camera != null && previewing) {
- autoFocusHandler = handler;
- autoFocusMessage = message;
+ autoFocusCallback.setHandler(handler, message);
camera.autoFocus(autoFocusCallback);
}
}
@@ -232,6 +205,7 @@ final class CameraManager {
* @return The rectangle to draw on screen in window coordinates.
*/
public Rect getFramingRect() {
+ Point cameraResolution = configManager.getCameraResolution();
if (framingRect == null) {
if (camera == null) {
return null;
@@ -257,56 +231,56 @@ final class CameraManager {
}
/**
- * Sets the camera up to take preview images which are used for both preview and decoding.
- * We detect the preview format here so that buildLuminanceSource() can build an appropriate
- * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
- * and the planar Y can be used for barcode scanning without a copy in some cases.
+ * Converts the result points from still resolution coordinates to screen coordinates.
+ *
+ * @param points The points returned by the Reader subclass through Result.getResultPoints().
+ * @return An array of Points scaled to the size of the framing rect and offset appropriately
+ * so they can be drawn in screen coordinates.
*/
- private void setCameraParameters() {
- Camera.Parameters parameters = camera.getParameters();
- Camera.Size size = parameters.getPreviewSize();
- Log.v(TAG, "Default preview size: " + size.width + ", " + size.height);
- previewFormat = parameters.getPreviewFormat();
- previewFormatString = parameters.get("preview-format");
- Log.v(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString);
-
- // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
- // TODO: A better solution would be to request the supported preview resolutions
- // and pick the best match, but this parameter is not standardized in Cupcake.
- cameraResolution = new Point();
- cameraResolution.x = (screenResolution.x >> 3) << 3;
- cameraResolution.y = (screenResolution.y >> 3) << 3;
- Log.v(TAG, "Setting preview size: " + cameraResolution.x + ", " + cameraResolution.y);
- parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
-
- // FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
- parameters.set("flash-value", 2);
-
- // This is the standard setting to turn the flash off that all devices should honor.
- parameters.set("flash-mode", "off");
-
- camera.setParameters(parameters);
- }
-
- private String collectCameraParameters() {
- Camera.Parameters parameters = camera.getParameters();
- String[] params = parameters.flatten().split(";");
- StringBuffer result = new StringBuffer();
- result.append("Default camera parameters:");
- for (String param : params) {
- result.append("\n ");
- result.append(param);
+ public Point[] convertResultPoints(ResultPoint[] points) {
+ Rect frame = getFramingRect();
+ int count = points.length;
+ Point[] output = new Point[count];
+ for (int x = 0; x < count; x++) {
+ output[x] = new Point();
+ output[x].x = frame.left + (int) (points[x].getX() + 0.5f);
+ output[x].y = frame.top + (int) (points[x].getY() + 0.5f);
}
- result.append('\n');
- return result.toString();
+ return output;
}
- private Point getScreenResolution() {
- if (screenResolution == null) {
- WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- Display display = manager.getDefaultDisplay();
- screenResolution = new Point(display.getWidth(), display.getHeight());
+ /**
+ * 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 = getFramingRect();
+ int previewFormat = configManager.getPreviewFormat();
+ String previewFormatString = configManager.getPreviewFormatString();
+ switch (previewFormat) {
+ // This is the standard Android format which all devices are REQUIRED to support.
+ // In theory, it's the only one we should ever care about.
+ case PixelFormat.YCbCr_420_SP:
+ // This format has never been seen in the wild, but is compatible as we only care
+ // about the Y channel, so allow it.
+ case PixelFormat.YCbCr_422_SP:
+ return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
+ rect.width(), rect.height());
+ default:
+ // The Samsung Moment incorrectly uses this variant instead of the 'sp' version.
+ // Fortunately, it too has all the Y data up front, so we can read it.
+ if ("yuv420p".equals(previewFormatString)) {
+ return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
+ rect.width(), rect.height());
+ }
}
- return screenResolution;
+ throw new IllegalArgumentException("Unsupported picture format: " +
+ previewFormat + '/' + previewFormatString);
}
+
}
diff --git a/android/src/com/google/zxing/client/android/FlashlightManager.java b/android/src/com/google/zxing/client/android/camera/FlashlightManager.java
similarity index 99%
rename from android/src/com/google/zxing/client/android/FlashlightManager.java
rename to android/src/com/google/zxing/client/android/camera/FlashlightManager.java
index 894d751..44459d1 100644
--- a/android/src/com/google/zxing/client/android/FlashlightManager.java
+++ b/android/src/com/google/zxing/client/android/camera/FlashlightManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.google.zxing.client.android;
+package com.google.zxing.client.android.camera;
import android.os.IBinder;
import android.util.Log;
diff --git a/android/src/com/google/zxing/client/android/camera/PreviewCallback.java b/android/src/com/google/zxing/client/android/camera/PreviewCallback.java
new file mode 100644
index 0000000..83377ba
--- /dev/null
+++ b/android/src/com/google/zxing/client/android/camera/PreviewCallback.java
@@ -0,0 +1,54 @@
+/*
+ * 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 com.google.zxing.client.android.camera;
+
+import android.graphics.Point;
+import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Message;
+
+final class PreviewCallback implements Camera.PreviewCallback {
+
+ private final CameraConfigurationManager configManager;
+ private final boolean useOneShotPreviewCallback;
+ private Handler previewHandler;
+ private int previewMessage;
+
+ PreviewCallback(CameraConfigurationManager configManager, boolean useOneShotPreviewCallback) {
+ this.configManager = configManager;
+ this.useOneShotPreviewCallback = useOneShotPreviewCallback;
+ }
+
+ void setHandler(Handler previewHandler, int previewMessage) {
+ this.previewHandler = previewHandler;
+ this.previewMessage = previewMessage;
+ }
+
+ public void onPreviewFrame(byte[] data, Camera camera) {
+ Point cameraResolution = configManager.getCameraResolution();
+ if (!useOneShotPreviewCallback) {
+ camera.setPreviewCallback(null);
+ }
+ if (previewHandler != null) {
+ Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x,
+ cameraResolution.y, data);
+ message.sendToTarget();
+ previewHandler = null;
+ }
+ }
+
+}
--
Multi-format 1D/2D barcode image processing library
More information about the Pkg-google-commits
mailing list