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:
dswitkin 2008-04-01 16:11:36 +00:00
parent 4b0927626f
commit 14a200b546
2 changed files with 141 additions and 20 deletions

View file

@ -61,7 +61,7 @@ public final class BarcodeReaderCaptureActivity extends Activity {
cameraManager = new CameraManager(getApplication());
surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
setContentView(surfaceView);
workerThread = new WorkerThread(surfaceView, cameraManager, messageHandler);
workerThread = new WorkerThread(this, surfaceView, cameraManager, messageHandler);
workerThread.requestPreviewLoop();
workerThread.start();
@ -82,7 +82,7 @@ public final class BarcodeReaderCaptureActivity extends Activity {
super.onResume();
cameraManager.openDriver();
if (workerThread == null) {
workerThread = new WorkerThread(surfaceView, cameraManager, messageHandler);
workerThread = new WorkerThread(this, surfaceView, cameraManager, messageHandler);
workerThread.requestPreviewLoop();
workerThread.start();
}
@ -102,10 +102,16 @@ public final class BarcodeReaderCaptureActivity extends Activity {
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
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 {
return super.onKeyDown(keyCode, event);
}
return true;
}
@Override

View file

@ -16,14 +16,25 @@
package com.google.zxing.client.android;
import android.app.Application;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MonochromeBitmapSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
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
* 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 {
private final BarcodeReaderCaptureActivity activity;
private final CameraSurfaceView surfaceView;
private final CameraManager cameraManager;
private final Handler handler;
@ -42,10 +54,15 @@ final class WorkerThread extends Thread {
IDLE,
PREVIEW_LOOP,
STILL_AND_DECODE,
STILL_AND_DECODE_1D,
STILL_AND_DECODE_QR,
STILL_AND_SAVE,
DONE
}
WorkerThread(CameraSurfaceView surfaceView, CameraManager cameraManager, Handler handler) {
WorkerThread(BarcodeReaderCaptureActivity activity, CameraSurfaceView surfaceView,
CameraManager cameraManager, Handler handler) {
this.activity = activity;
this.surfaceView = surfaceView;
this.cameraManager = cameraManager;
this.handler = handler;
@ -64,20 +81,33 @@ final class WorkerThread extends Thread {
surfaceView.capturePreviewAndDraw();
break;
case STILL_AND_DECODE:
Bitmap bitmap = cameraManager.captureStill();
Result rawResult;
try {
MonochromeBitmapSource source = new RGBMonochromeBitmapSource(bitmap);
rawResult = new MultiFormatReader().decode(source);
} catch (ReaderException e) {
Message message = Message.obtain(handler, R.id.decoding_failed_message);
message.sendToTarget();
state = State.PREVIEW_LOOP;
break;
}
Message message = Message.obtain(handler, R.id.decoding_succeeded_message, rawResult);
message.sendToTarget();
state = State.IDLE;
takeStillAndDecode(null);
break;
case STILL_AND_DECODE_1D: {
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
// TODO: This is fragile in case we add new formats. It would be better to have a new enum
// value which represented all 1D formats.
Vector vector = new Vector();
vector.addElement(BarcodeFormat.UPC_A);
vector.addElement(BarcodeFormat.UPC_E);
vector.addElement(BarcodeFormat.EAN_13);
vector.addElement(BarcodeFormat.EAN_8);
vector.addElement(BarcodeFormat.CODE_39);
vector.addElement(BarcodeFormat.CODE_128);
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;
case DONE:
return;
@ -95,6 +125,21 @@ final class WorkerThread extends Thread {
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() {
state = State.DONE;
wakeFromIdle();
@ -109,8 +154,8 @@ final class WorkerThread extends Thread {
synchronized (idleLock) {
idleLock.wait();
}
} catch (InterruptedException ie) {
// continue
} catch (InterruptedException e) {
// 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";
}
}