mirror of
https://github.com/zxing/zxing.git
synced 2024-11-10 13:04:05 -08:00
Added some debugging features to the M3 Android client. You can now press 'C' to capture a photo, 'U' to decode only UPC/1D barcodes, and 'Q' to decode only QR Codes.
git-svn-id: https://zxing.googlecode.com/svn/trunk@332 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
4b0927626f
commit
14a200b546
|
@ -61,7 +61,7 @@ public final class BarcodeReaderCaptureActivity extends Activity {
|
||||||
cameraManager = new CameraManager(getApplication());
|
cameraManager = new CameraManager(getApplication());
|
||||||
surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
|
surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
|
||||||
setContentView(surfaceView);
|
setContentView(surfaceView);
|
||||||
workerThread = new WorkerThread(surfaceView, cameraManager, messageHandler);
|
workerThread = new WorkerThread(this, surfaceView, cameraManager, messageHandler);
|
||||||
workerThread.requestPreviewLoop();
|
workerThread.requestPreviewLoop();
|
||||||
workerThread.start();
|
workerThread.start();
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ public final class BarcodeReaderCaptureActivity extends Activity {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
cameraManager.openDriver();
|
cameraManager.openDriver();
|
||||||
if (workerThread == null) {
|
if (workerThread == null) {
|
||||||
workerThread = new WorkerThread(surfaceView, cameraManager, messageHandler);
|
workerThread = new WorkerThread(this, surfaceView, cameraManager, messageHandler);
|
||||||
workerThread.requestPreviewLoop();
|
workerThread.requestPreviewLoop();
|
||||||
workerThread.start();
|
workerThread.start();
|
||||||
}
|
}
|
||||||
|
@ -102,10 +102,16 @@ public final class BarcodeReaderCaptureActivity extends Activity {
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
|
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
|
||||||
workerThread.requestStillAndDecode();
|
workerThread.requestStillAndDecode();
|
||||||
return true;
|
} else if (keyCode == KeyEvent.KEYCODE_Q) {
|
||||||
|
workerThread.requestStillAndDecodeQR();
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_U) {
|
||||||
|
workerThread.requestStillAndDecode1D();
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_C) {
|
||||||
|
workerThread.requestStillAndSave();
|
||||||
} else {
|
} else {
|
||||||
return super.onKeyDown(keyCode, event);
|
return super.onKeyDown(keyCode, event);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,14 +16,25 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
package com.google.zxing.client.android;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.DecodeHintType;
|
||||||
import com.google.zxing.MonochromeBitmapSource;
|
import com.google.zxing.MonochromeBitmapSource;
|
||||||
import com.google.zxing.MultiFormatReader;
|
import com.google.zxing.MultiFormatReader;
|
||||||
import com.google.zxing.ReaderException;
|
import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This thread does all the heavy lifting, both during preview and for the final capture and
|
* This thread does all the heavy lifting, both during preview and for the final capture and
|
||||||
* decoding. That leaves the main thread free to handle UI tasks.
|
* decoding. That leaves the main thread free to handle UI tasks.
|
||||||
|
@ -32,6 +43,7 @@ import com.google.zxing.Result;
|
||||||
*/
|
*/
|
||||||
final class WorkerThread extends Thread {
|
final class WorkerThread extends Thread {
|
||||||
|
|
||||||
|
private final BarcodeReaderCaptureActivity activity;
|
||||||
private final CameraSurfaceView surfaceView;
|
private final CameraSurfaceView surfaceView;
|
||||||
private final CameraManager cameraManager;
|
private final CameraManager cameraManager;
|
||||||
private final Handler handler;
|
private final Handler handler;
|
||||||
|
@ -42,10 +54,15 @@ final class WorkerThread extends Thread {
|
||||||
IDLE,
|
IDLE,
|
||||||
PREVIEW_LOOP,
|
PREVIEW_LOOP,
|
||||||
STILL_AND_DECODE,
|
STILL_AND_DECODE,
|
||||||
|
STILL_AND_DECODE_1D,
|
||||||
|
STILL_AND_DECODE_QR,
|
||||||
|
STILL_AND_SAVE,
|
||||||
DONE
|
DONE
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkerThread(CameraSurfaceView surfaceView, CameraManager cameraManager, Handler handler) {
|
WorkerThread(BarcodeReaderCaptureActivity activity, CameraSurfaceView surfaceView,
|
||||||
|
CameraManager cameraManager, Handler handler) {
|
||||||
|
this.activity = activity;
|
||||||
this.surfaceView = surfaceView;
|
this.surfaceView = surfaceView;
|
||||||
this.cameraManager = cameraManager;
|
this.cameraManager = cameraManager;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
|
@ -64,20 +81,33 @@ final class WorkerThread extends Thread {
|
||||||
surfaceView.capturePreviewAndDraw();
|
surfaceView.capturePreviewAndDraw();
|
||||||
break;
|
break;
|
||||||
case STILL_AND_DECODE:
|
case STILL_AND_DECODE:
|
||||||
Bitmap bitmap = cameraManager.captureStill();
|
takeStillAndDecode(null);
|
||||||
Result rawResult;
|
break;
|
||||||
try {
|
case STILL_AND_DECODE_1D: {
|
||||||
MonochromeBitmapSource source = new RGBMonochromeBitmapSource(bitmap);
|
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
|
||||||
rawResult = new MultiFormatReader().decode(source);
|
// TODO: This is fragile in case we add new formats. It would be better to have a new enum
|
||||||
} catch (ReaderException e) {
|
// value which represented all 1D formats.
|
||||||
Message message = Message.obtain(handler, R.id.decoding_failed_message);
|
Vector vector = new Vector();
|
||||||
message.sendToTarget();
|
vector.addElement(BarcodeFormat.UPC_A);
|
||||||
state = State.PREVIEW_LOOP;
|
vector.addElement(BarcodeFormat.UPC_E);
|
||||||
break;
|
vector.addElement(BarcodeFormat.EAN_13);
|
||||||
}
|
vector.addElement(BarcodeFormat.EAN_8);
|
||||||
Message message = Message.obtain(handler, R.id.decoding_succeeded_message, rawResult);
|
vector.addElement(BarcodeFormat.CODE_39);
|
||||||
message.sendToTarget();
|
vector.addElement(BarcodeFormat.CODE_128);
|
||||||
state = State.IDLE;
|
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
||||||
|
takeStillAndDecode(hints);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STILL_AND_DECODE_QR: {
|
||||||
|
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
|
||||||
|
Vector vector = new Vector();
|
||||||
|
vector.addElement(BarcodeFormat.QR_CODE);
|
||||||
|
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
||||||
|
takeStillAndDecode(hints);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STILL_AND_SAVE:
|
||||||
|
takeStillAndSave();
|
||||||
break;
|
break;
|
||||||
case DONE:
|
case DONE:
|
||||||
return;
|
return;
|
||||||
|
@ -95,6 +125,21 @@ final class WorkerThread extends Thread {
|
||||||
wakeFromIdle();
|
wakeFromIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void requestStillAndDecode1D() {
|
||||||
|
state = State.STILL_AND_DECODE_1D;
|
||||||
|
wakeFromIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestStillAndDecodeQR() {
|
||||||
|
state = State.STILL_AND_DECODE_QR;
|
||||||
|
wakeFromIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestStillAndSave() {
|
||||||
|
state = State.STILL_AND_SAVE;
|
||||||
|
wakeFromIdle();
|
||||||
|
}
|
||||||
|
|
||||||
public void requestExitAndWait() {
|
public void requestExitAndWait() {
|
||||||
state = State.DONE;
|
state = State.DONE;
|
||||||
wakeFromIdle();
|
wakeFromIdle();
|
||||||
|
@ -109,8 +154,8 @@ final class WorkerThread extends Thread {
|
||||||
synchronized (idleLock) {
|
synchronized (idleLock) {
|
||||||
idleLock.wait();
|
idleLock.wait();
|
||||||
}
|
}
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException e) {
|
||||||
// continue
|
// Continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,4 +165,74 @@ final class WorkerThread extends Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void takeStillAndDecode(Hashtable<DecodeHintType, Object> hints) {
|
||||||
|
Bitmap bitmap = cameraManager.captureStill();
|
||||||
|
Result rawResult;
|
||||||
|
try {
|
||||||
|
MonochromeBitmapSource source = new RGBMonochromeBitmapSource(bitmap);
|
||||||
|
rawResult = new MultiFormatReader().decode(source, hints);
|
||||||
|
} catch (ReaderException e) {
|
||||||
|
Message message = Message.obtain(handler, R.id.decoding_failed_message);
|
||||||
|
message.sendToTarget();
|
||||||
|
state = State.PREVIEW_LOOP;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Message message = Message.obtain(handler, R.id.decoding_succeeded_message, rawResult);
|
||||||
|
message.sendToTarget();
|
||||||
|
state = State.IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a debugging feature used to take photos and save them as JPEGs using the exact camera
|
||||||
|
* setup as in normal decoding. This is useful for building up a library of test images.
|
||||||
|
*/
|
||||||
|
private void takeStillAndSave() {
|
||||||
|
Bitmap bitmap = cameraManager.captureStill();
|
||||||
|
OutputStream outStream = getNewPhotoOutputStream();
|
||||||
|
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outStream);
|
||||||
|
try {
|
||||||
|
outStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
state = State.PREVIEW_LOOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We prefer to write to the SD Card because it has more space, and is automatically mounted as a
|
||||||
|
* drive over USB. If it's not present, fall back to the package's private file area here:
|
||||||
|
*
|
||||||
|
* /data/data/com.google.zxing.client.android/files
|
||||||
|
*
|
||||||
|
* @return A stream which represents the new file where the photo will be saved.
|
||||||
|
*/
|
||||||
|
private OutputStream getNewPhotoOutputStream() {
|
||||||
|
File sdcard = new File("/sdcard");
|
||||||
|
if (sdcard.exists()) {
|
||||||
|
File barcodes = new File(sdcard, "barcodes");
|
||||||
|
if (!barcodes.exists()) {
|
||||||
|
if (!barcodes.mkdir()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String fileName = getNewPhotoName(barcodes.list());
|
||||||
|
try {
|
||||||
|
return new FileOutputStream(new File(barcodes, fileName));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Application application = activity.getApplication();
|
||||||
|
String fileName = getNewPhotoName(application.fileList());
|
||||||
|
try {
|
||||||
|
return application.openFileOutput(fileName, 0);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getNewPhotoName(String[] listOfFiles) {
|
||||||
|
int existingFileCount = (listOfFiles != null) ? listOfFiles.length : 0;
|
||||||
|
return "capture" + existingFileCount + ".jpg";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue