Browse Source

feat:zbar上传

lihao1 3 years ago
parent
commit
bcbb2f4d54

+ 1 - 0
demo/src/main/java/com/sybotan/android/demo/activities/GraphyActivity.kt

@@ -178,6 +178,7 @@ class GraphyActivity : BaseActivity() {
             when (name) {
                 GraphyVM.SPACE_JOB -> {
                     val list = params as (List<SpaceJobModel>)
+
                 }
             }
         }, this)

+ 5 - 11
demo/src/main/java/com/sybotan/android/demo/viewmodel/GraphyVM.java

@@ -27,22 +27,16 @@ public class GraphyVM extends BaseViewModel {
 
     public void getSpaceJob() {
         ReqSpaceJob bean = new ReqSpaceJob();
-        bean.buildingId="Bd00022200113a69205aebc34aba87b31a2a03a572ab";
-        bean.floorId="Fl00022200115d43d88abaab46cda43f1596b5e3930b";
+        bean.buildingId = "Bd00022200113a69205aebc34aba87b31a2a03a572ab";
+        bean.floorId = "Fl00022200115d43d88abaab46cda43f1596b5e3930b";
         bean.jobStatus.add("01");
         bean.jobStatus.add("02");
         Observable<BaseModel<List<SpaceJobModel>>> observable = RetrofitFactory.getInstance().getSpaceJob(getRequestBody(bean));
-        sendRequest(observable, new BaseObserver<List<SpaceJobModel>>(mActivity,this) {
+        sendRequest(observable, new BaseObserver<List<SpaceJobModel>>(mActivity, this) {
             @Override
             protected void onSuccess(List<SpaceJobModel> spaceJobModels) {
-                mEmitter.SendDircetive(SPACE_JOB,spaceJobModels);
+                mEmitter.SendDircetive(SPACE_JOB, spaceJobModels);
             }
-        },true);
-//        sendRequest(observable, new BaseObserver<List<SpaceJobModel>>(mActivity, this) {
-//            @Override
-//            protected void onSuccess(List<SpaceJobModel> spaceJobModels) {
-//                mEmitter.SendDircetive(SPACE_JOB, spaceJobModels);
-//            }
-//        }, true);
+        }, true);
     }
 }

+ 13 - 0
demo/src/main/java/com/zbar/lib/ZbarManager.java

@@ -0,0 +1,13 @@
+package com.zbar.lib;
+
+/**
+ * zbar调用类
+ */
+public class ZbarManager {
+
+	static {
+		System.loadLibrary("zbar");
+	}
+
+	public native String decode(byte[] data, int width, int height, boolean isCrop, int x, int y, int cwidth, int cheight);
+}

+ 67 - 0
demo/src/main/java/com/zbar/lib/bitmap/InvertedLuminanceSource.java

@@ -0,0 +1,67 @@
+package com.zbar.lib.bitmap;
+
+public final class InvertedLuminanceSource extends LuminanceSource {
+
+	private final LuminanceSource delegate;
+
+	public InvertedLuminanceSource(LuminanceSource delegate) {
+		super(delegate.getWidth(), delegate.getHeight());
+		this.delegate = delegate;
+	}
+
+	@Override
+	public byte[] getRow(int y, byte[] row) {
+		row = delegate.getRow(y, row);
+		int width = getWidth();
+		for (int i = 0; i < width; i++) {
+			row[i] = (byte) (255 - (row[i] & 0xFF));
+		}
+		return row;
+	}
+
+	@Override
+	public byte[] getMatrix() {
+		byte[] matrix = delegate.getMatrix();
+		int length = getWidth() * getHeight();
+		byte[] invertedMatrix = new byte[length];
+		for (int i = 0; i < length; i++) {
+			invertedMatrix[i] = (byte) (255 - (matrix[i] & 0xFF));
+		}
+		return invertedMatrix;
+	}
+
+	@Override
+	public boolean isCropSupported() {
+		return delegate.isCropSupported();
+	}
+
+	@Override
+	public LuminanceSource crop(int left, int top, int width, int height) {
+		return new InvertedLuminanceSource(delegate.crop(left, top, width, height));
+	}
+
+	@Override
+	public boolean isRotateSupported() {
+		return delegate.isRotateSupported();
+	}
+
+	/**
+	 * @return original delegate {@link LuminanceSource} since invert undoes
+	 *         itself
+	 */
+	@Override
+	public LuminanceSource invert() {
+		return delegate;
+	}
+
+	@Override
+	public LuminanceSource rotateCounterClockwise() {
+		return new InvertedLuminanceSource(delegate.rotateCounterClockwise());
+	}
+
+	@Override
+	public LuminanceSource rotateCounterClockwise45() {
+		return new InvertedLuminanceSource(delegate.rotateCounterClockwise45());
+	}
+
+}

+ 142 - 0
demo/src/main/java/com/zbar/lib/bitmap/LuminanceSource.java

@@ -0,0 +1,142 @@
+package com.zbar.lib.bitmap;
+
+public abstract class LuminanceSource {
+
+	private final int width;
+	private final int height;
+
+	protected LuminanceSource(int width, int height) {
+		this.width = width;
+		this.height = height;
+	}
+
+	/**
+	 * Fetches one row of luminance data from the underlying platform's bitmap.
+	 * Values range from 0 (black) to 255 (white). Because Java does not have an
+	 * unsigned byte type, callers will have to bitwise and with 0xff for each
+	 * value. It is preferable for implementations of this method to only fetch
+	 * this row rather than the whole image, since no 2D Readers may be
+	 * installed and getMatrix() may never be called.
+	 * 
+	 * @param y
+	 *            The row to fetch, which must be in [0,getHeight())
+	 * @param row
+	 *            An optional preallocated array. If null or too small, it will
+	 *            be ignored. Always use the returned object, and ignore the
+	 *            .length of the array.
+	 * @return An array containing the luminance data.
+	 */
+	public abstract byte[] getRow(int y, byte[] row);
+
+	/**
+	 * Fetches luminance data for the underlying bitmap. Values should be
+	 * fetched using: {@code int luminance = array[y * width + x] & 0xff}
+	 * 
+	 * @return A row-major 2D array of luminance values. Do not use
+	 *         result.length as it may be larger than width * height bytes on
+	 *         some platforms. Do not modify the mList_contents of the result.
+	 */
+	public abstract byte[] getMatrix();
+
+	/**
+	 * @return The width of the bitmap.
+	 */
+	public final int getWidth() {
+		return width;
+	}
+
+	/**
+	 * @return The height of the bitmap.
+	 */
+	public final int getHeight() {
+		return height;
+	}
+
+	/**
+	 * @return Whether this subclass supports cropping.
+	 */
+	public boolean isCropSupported() {
+		return false;
+	}
+
+	/**
+	 * Returns a new object with cropped image data. Implementations may keep a
+	 * reference to the original data rather than a copy. Only callable if
+	 * isCropSupported() is true.
+	 * 
+	 * @param left
+	 *            The left coordinate, which must be in [0,getWidth())
+	 * @param top
+	 *            The top coordinate, which must be in [0,getHeight())
+	 * @param width
+	 *            The width of the rectangle to crop.
+	 * @param height
+	 *            The height of the rectangle to crop.
+	 * @return A cropped version of this object.
+	 */
+	public LuminanceSource crop(int left, int top, int width, int height) {
+		throw new UnsupportedOperationException("This luminance source does not support cropping.");
+	}
+
+	/**
+	 * @return Whether this subclass supports counter-clockwise rotation.
+	 */
+	public boolean isRotateSupported() {
+		return false;
+	}
+
+	/**
+	 * @return a wrapper of this {@code LuminanceSource} which inverts the
+	 *         luminances it returns -- black becomes white and vice versa, and
+	 *         each value becomes (255-value).
+	 */
+	public LuminanceSource invert() {
+		return new InvertedLuminanceSource(this);
+	}
+
+	/**
+	 * Returns a new object with rotated image data by 90 degrees
+	 * counterclockwise. Only callable if {@link #isRotateSupported()} is true.
+	 * 
+	 * @return A rotated version of this object.
+	 */
+	public LuminanceSource rotateCounterClockwise() {
+		throw new UnsupportedOperationException("This luminance source does not support rotation by 90 degrees.");
+	}
+
+	/**
+	 * Returns a new object with rotated image data by 45 degrees
+	 * counterclockwise. Only callable if {@link #isRotateSupported()} is true.
+	 * 
+	 * @return A rotated version of this object.
+	 */
+	public LuminanceSource rotateCounterClockwise45() {
+		throw new UnsupportedOperationException("This luminance source does not support rotation by 45 degrees.");
+	}
+
+	@Override
+	public final String toString() {
+		byte[] row = new byte[width];
+		StringBuilder result = new StringBuilder(height * (width + 1));
+		for (int y = 0; y < height; y++) {
+			row = getRow(y, row);
+			for (int x = 0; x < width; x++) {
+				int luminance = row[x] & 0xFF;
+				char c;
+				if (luminance < 0x40) {
+					c = '#';
+				} else if (luminance < 0x80) {
+					c = '+';
+				} else if (luminance < 0xC0) {
+					c = '.';
+				} else {
+					c = ' ';
+				}
+				result.append(c);
+			}
+			result.append('\n');
+		}
+		return result.toString();
+	}
+
+}

+ 132 - 0
demo/src/main/java/com/zbar/lib/bitmap/PlanarYUVLuminanceSource.java

@@ -0,0 +1,132 @@
+package com.zbar.lib.bitmap;
+
+public final class PlanarYUVLuminanceSource extends LuminanceSource {
+
+	private static final int THUMBNAIL_SCALE_FACTOR = 2;
+
+	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;
+	}
+
+	@Override
+	public LuminanceSource crop(int left, int top, int width, int height) {
+		return new PlanarYUVLuminanceSource(yuvData, dataWidth, dataHeight, this.left + left, this.top + top, width, height, false);
+	}
+
+	public int[] renderThumbnail() {
+		int width = getWidth() / THUMBNAIL_SCALE_FACTOR;
+		int height = getHeight() / THUMBNAIL_SCALE_FACTOR;
+		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 * THUMBNAIL_SCALE_FACTOR] & 0xff;
+				pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101);
+			}
+			inputOffset += dataWidth * THUMBNAIL_SCALE_FACTOR;
+		}
+		return pixels;
+	}
+
+	/**
+	 * @return width of image from {@link #renderThumbnail()}
+	 */
+	public int getThumbnailWidth() {
+		return getWidth() / THUMBNAIL_SCALE_FACTOR;
+	}
+
+	/**
+	 * @return height of image from {@link #renderThumbnail()}
+	 */
+	public int getThumbnailHeight() {
+		return getHeight() / THUMBNAIL_SCALE_FACTOR;
+	}
+
+	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;
+			}
+		}
+	}
+
+}

+ 35 - 0
demo/src/main/java/com/zbar/lib/camera/AutoFocusCallback.java

@@ -0,0 +1,35 @@
+package com.zbar.lib.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);
+			autoFocusHandler.sendMessageDelayed(message, AUTOFOCUS_INTERVAL_MS);
+			autoFocusHandler = null;
+		} else {
+			Log.d(TAG, "Got auto-focus callback, but no handler for it");
+		}
+	}
+
+}

+ 245 - 0
demo/src/main/java/com/zbar/lib/camera/CameraConfigurationManager.java

@@ -0,0 +1,245 @@
+package com.zbar.lib.camera;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.hardware.Camera;
+import android.os.Build;
+import android.util.Log;
+import android.view.Display;
+import android.view.WindowManager;
+
+import java.util.regex.Pattern;
+
+/**
+ * 相机参数配置
+ */
+final class CameraConfigurationManager {
+
+	private static final String TAG = CameraConfigurationManager.class
+			.getSimpleName();
+
+	private static final int TEN_DESIRED_ZOOM = 27;
+	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;
+	}
+
+	@SuppressWarnings("deprecation")
+	void initFromCameraParameters(Camera camera) {
+		Camera.Parameters parameters = camera.getParameters();
+		previewFormat = parameters.getPreviewFormat();
+		previewFormatString = parameters.get("preview-format");
+		WindowManager manager = (WindowManager) context
+				.getSystemService(Context.WINDOW_SERVICE);
+		Display display = manager.getDefaultDisplay();
+		screenResolution = new Point(display.getWidth(), display.getHeight());
+		
+	    Point screenResolutionForCamera = new Point();
+	    screenResolutionForCamera.x = screenResolution.x;   
+	    screenResolutionForCamera.y = screenResolution.y;
+	    
+	    if (screenResolution.x < screenResolution.y) {  
+	         screenResolutionForCamera.x = screenResolution.y;  
+	         screenResolutionForCamera.y = screenResolution.x;
+	    }
+		cameraResolution = getCameraResolution(parameters, screenResolutionForCamera);
+	}
+	
+	void setDesiredCameraParameters(Camera camera) {
+		Camera.Parameters parameters = camera.getParameters();
+		parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
+		setFlash(parameters);
+		setZoom(parameters);
+		
+		camera.setDisplayOrientation(90);
+		camera.setParameters(parameters);
+	}
+
+	Point getCameraResolution() {
+		return cameraResolution;
+	}
+
+	Point getScreenResolution() {
+		return screenResolution;
+	}
+
+	int getPreviewFormat() {
+		return previewFormat;
+	}
+
+	String getPreviewFormatString() {
+		return previewFormatString;
+	}
+
+	private static Point getCameraResolution(Camera.Parameters parameters,
+			Point screenResolution) {
+
+		String previewSizeValueString = parameters.get("preview-size-values");
+		if (previewSizeValueString == null) {
+			previewSizeValueString = parameters.get("preview-size-value");
+		}
+
+		Point cameraResolution = null;
+
+		if (previewSizeValueString != null) {
+			cameraResolution = findBestPreviewSizeValue(previewSizeValueString,
+					screenResolution);
+		}
+
+		if (cameraResolution == null) {
+			cameraResolution = new Point((screenResolution.x >> 3) << 3,
+					(screenResolution.y >> 3) << 3);
+		}
+
+		return cameraResolution;
+	}
+
+	private static Point findBestPreviewSizeValue(
+			CharSequence 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) {
+				continue;
+			}
+
+			int newX;
+			int newY;
+			try {
+				newX = Integer.parseInt(previewSize.substring(0, dimPosition));
+				newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
+			} catch (NumberFormatException nfe) {
+				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(CharSequence 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) {
+		if (Build.MODEL.contains("Behold II") && CameraManager.SDK_INT == 3) { // 3
+			parameters.set("flash-value", 1);
+		} else {
+			parameters.set("flash-value", 2);
+		}
+		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);
+		}
+	}
+
+}

+ 153 - 0
demo/src/main/java/com/zbar/lib/camera/CameraManager.java

@@ -0,0 +1,153 @@
+package com.zbar.lib.camera;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.hardware.Camera;
+import android.hardware.Camera.Parameters;
+import android.os.Handler;
+import android.view.SurfaceHolder;
+
+import java.io.IOException;
+
+/**
+ * 相机管理
+ */
+public final class CameraManager {
+    private static CameraManager cameraManager;
+
+    static final int SDK_INT;
+
+    static {
+        int sdkInt;
+        try {
+            sdkInt = android.os.Build.VERSION.SDK_INT;
+        } catch (NumberFormatException nfe) {
+            sdkInt = 10000;
+        }
+        SDK_INT = sdkInt;
+    }
+
+    private final CameraConfigurationManager configManager;
+    private Camera camera;
+    private boolean initialized;
+    private boolean previewing;
+    private final boolean useOneShotPreviewCallback;
+    private final PreviewCallback previewCallback;
+    private final AutoFocusCallback autoFocusCallback;
+    private Parameters parameter;
+
+    public static void init(Context context) {
+        if (cameraManager == null) {
+            cameraManager = new CameraManager(context);
+        }
+    }
+
+    public static CameraManager get() {
+        return cameraManager;
+    }
+
+    public CameraManager(Context context) {
+        this.configManager = new CameraConfigurationManager(context);
+
+        useOneShotPreviewCallback = SDK_INT > 3;
+        previewCallback = new PreviewCallback(configManager, useOneShotPreviewCallback);
+        autoFocusCallback = new AutoFocusCallback();
+    }
+
+    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;
+                configManager.initFromCameraParameters(camera);
+            }
+            configManager.setDesiredCameraParameters(camera);
+            FlashlightManager.enableFlashlight();
+        }
+    }
+
+    public Point getCameraResolution() {
+        return configManager.getCameraResolution();
+    }
+
+    public void closeDriver() {
+//        if (camera != null) {
+//            FlashlightManager.disableFlashlight();
+//            camera.release();
+//            camera = null;
+//        }
+
+        if (camera != null) {
+            FlashlightManager.disableFlashlight();
+            if (previewing) {
+                camera.stopPreview();
+            }
+
+            camera.release();
+            camera = null;
+            previewing = false;
+        }
+    }
+
+    public void startPreview() {
+        if (camera != null && !previewing) {
+            camera.startPreview();
+            previewing = true;
+        }
+    }
+
+    public void stopPreview() {
+        if (camera != null && previewing) {
+            if (!useOneShotPreviewCallback) {
+                camera.setPreviewCallback(null);
+            }
+            camera.stopPreview();
+            previewCallback.setHandler(null, 0);
+            autoFocusCallback.setHandler(null, 0);
+            previewing = false;
+        }
+    }
+
+    public void requestPreviewFrame(Handler handler, int message) {
+        if (camera != null && previewing) {
+            previewCallback.setHandler(handler, message);
+            if (useOneShotPreviewCallback) {
+                camera.setOneShotPreviewCallback(previewCallback);
+            } else {
+                camera.setPreviewCallback(previewCallback);
+            }
+        }
+    }
+
+    public void requestAutoFocus(Handler handler, int message) {
+        if (camera != null && previewing) {
+            autoFocusCallback.setHandler(handler, message);
+            camera.autoFocus(autoFocusCallback);
+        }
+    }
+
+    public void autoFocus() {
+        camera.autoFocus(autoFocusCallback);
+    }
+
+    public void openLight() {
+        if (camera != null) {
+            parameter = camera.getParameters();
+            parameter.setFlashMode(Parameters.FLASH_MODE_TORCH);
+            camera.setParameters(parameter);
+        }
+    }
+
+    public void offLight() {
+        if (camera != null) {
+            parameter = camera.getParameters();
+            parameter.setFlashMode(Parameters.FLASH_MODE_OFF);
+            camera.setParameters(parameter);
+        }
+    }
+}

+ 121 - 0
demo/src/main/java/com/zbar/lib/camera/FlashlightManager.java

@@ -0,0 +1,121 @@
+package com.zbar.lib.camera;
+
+import android.os.IBinder;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * 闪光灯管理
+ */
+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);
+    }
+  }
+
+}

+ 46 - 0
demo/src/main/java/com/zbar/lib/camera/PreviewCallback.java

@@ -0,0 +1,46 @@
+package com.zbar.lib.camera;
+
+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 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;
+    } else {
+      Log.d(TAG, "Got preview callback, but no handler for it");
+    }
+  }
+
+}

+ 27 - 0
demo/src/main/java/com/zbar/lib/decode/FinishListener.java

@@ -0,0 +1,27 @@
+package com.zbar.lib.decode;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+
+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();
+  }
+
+}