diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 8f925eb85..3d614d8fa 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -1,11 +1,26 @@ - + + - + - - + + diff --git a/android/build.xml b/android/build.xml index 57b6d5379..2400b1321 100644 --- a/android/build.xml +++ b/android/build.xml @@ -1,5 +1,4 @@ - - + @@ -51,8 +51,9 @@ + + - @@ -119,6 +120,8 @@ + + @@ -185,7 +188,7 @@ - + @@ -245,7 +248,11 @@ only when the assets dir exists. --> update="true"/> - + Packaging dex... @@ -258,6 +265,15 @@ only when the assets dir exists. --> + + + Sending package to default emulator... + + + + + + diff --git a/android/src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java b/android/src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java index 31966552d..a682c438e 100644 --- a/android/src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java +++ b/android/src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java @@ -19,14 +19,12 @@ package com.google.zxing.client.android; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.graphics.PixelFormat; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.KeyEvent; import android.view.Menu; import android.view.Window; -import android.view.WindowManager.LayoutParams; import com.google.zxing.Result; import com.google.zxing.ResultPoint; import com.google.zxing.client.result.ParsedReaderResult; @@ -52,12 +50,6 @@ public final class BarcodeReaderCaptureActivity extends Activity { super.onCreate(icicle); requestWindowFeature(Window.FEATURE_NO_TITLE); - // Make sure to create a TRANSLUCENT window. This is required for SurfaceView to work. - // Eventually this'll be done by the system automatically. - getWindow().setAttributes(new LayoutParams(LayoutParams.APPLICATION_TYPE, - LayoutParams.NO_STATUS_BAR_FLAG)); - getWindow().setFormat(PixelFormat.TRANSLUCENT); - cameraManager = new CameraManager(getApplication()); surfaceView = new CameraSurfaceView(getApplication(), cameraManager); setContentView(surfaceView); @@ -69,14 +61,6 @@ public final class BarcodeReaderCaptureActivity extends Activity { //GridSampler.setGridSampler(new AndroidGraphicsGridSampler()); } - @Override - protected boolean isFullscreenOpaque() { - // Our main window is set to translucent, but we know that we will - // fill it with opaque data. Tell the system that so it can perform - // some important optimizations. - return true; - } - @Override protected void onResume() { super.onResume(); @@ -120,9 +104,12 @@ public final class BarcodeReaderCaptureActivity extends Activity { switch (item.getId()) { case ABOUT_ID: Context context = getApplication(); - showAlert(context.getString(R.string.title_about), - context.getString(R.string.msg_about), - context.getString(R.string.button_ok), null, true, null); + showAlert( + context.getString(R.string.title_about), + 0, + context.getString(R.string.msg_about), + context.getString(R.string.button_ok), + true); break; } return super.onOptionsItemSelected(item); @@ -137,9 +124,12 @@ public final class BarcodeReaderCaptureActivity extends Activity { break; case R.id.decoding_failed_message: Context context = getApplication(); - showAlert(context.getString(R.string.title_no_barcode_detected), - context.getString(R.string.msg_no_barcode_detected), - context.getString(R.string.button_ok), null, true, null); + showAlert( + context.getString(R.string.title_no_barcode_detected), + 0, + context.getString(R.string.msg_no_barcode_detected), + context.getString(R.string.button_ok), + true); break; } } @@ -149,7 +139,6 @@ public final class BarcodeReaderCaptureActivity extends Activity { workerThread.requestPreviewLoop(); } - // TODO(dswitkin): These deprecated showAlert calls need to be updated. private void handleDecode(Result rawResult) { ResultPoint[] points = rawResult.getResultPoints(); if (points != null && points.length > 0) { @@ -162,17 +151,26 @@ public final class BarcodeReaderCaptureActivity extends Activity { if (handler.getIntent() != null) { // Can be handled by some external app; ask if the user wants to // proceed first though - Message yesMessage = handler.obtainMessage(R.string.button_yes); - Message noMessage = handler.obtainMessage(R.string.button_no); - showAlert(context.getString(getDialogTitleID(readerResult.getType())), - readerResult.getDisplayResult(), context.getString(R.string.button_yes), - yesMessage, context.getString(R.string.button_no), noMessage, true, noMessage); + showAlert( + context.getString(getDialogTitleID(readerResult.getType())), + 0, + readerResult.getDisplayResult(), + context.getString(R.string.button_yes), + handler, + context.getString(R.string.button_no), + null, + true, + null + ); + } else { // Just show information to user - Message okMessage = handler.obtainMessage(R.string.button_ok); - showAlert(context.getString(R.string.title_barcode_detected), - readerResult.getDisplayResult(), context.getString(R.string.button_ok), okMessage, null, - null, true, okMessage); + showAlert( + context.getString(R.string.title_barcode_detected), + 0, + readerResult.getDisplayResult(), + context.getString(R.string.button_ok), + true); } } diff --git a/android/src/com/google/zxing/client/android/CameraManager.java b/android/src/com/google/zxing/client/android/CameraManager.java index 0cd3782f6..6bcf7487b 100644 --- a/android/src/com/google/zxing/client/android/CameraManager.java +++ b/android/src/com/google/zxing/client/android/CameraManager.java @@ -18,6 +18,7 @@ package com.google.zxing.client.android; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Point; import android.graphics.Rect; @@ -26,6 +27,8 @@ import android.util.Log; import android.view.Display; import android.view.WindowManager; import com.google.zxing.ResultPoint; +import com.tomgibara.android.camera.BitmapCamera; +import com.tomgibara.android.camera.CameraSource; /** * This object wraps the CameraDevice and expects to be the only one talking to it. The @@ -45,7 +48,10 @@ final class CameraManager { private Point screenResolution; private Rect framingRect; private final Bitmap bitmap; - private CameraDevice camera; + // TODO switch back to CameraDevice later + // private CameraDevice camera; + private CameraSource cameraSource; + // end TODO private final CameraDevice.CaptureParams params; private boolean previewMode; @@ -54,34 +60,51 @@ final class CameraManager { calculateStillResolution(); getScreenResolution(); bitmap = Bitmap.createBitmap(stillResolution.x, stillResolution.y, false); - camera = CameraDevice.open(); + // TODO switch back to CameraDevice later + // camera = CameraDevice.open(); + Bitmap fakeBitmap = BitmapFactory.decodeFile("/tmp/barcode.jpg"); + if (fakeBitmap == null) { + throw new RuntimeException("/tmp/barcode.jpg was not found"); + } + cameraSource = new BitmapCamera(fakeBitmap, stillResolution.x, stillResolution.y); + // end TODO params = new CameraDevice.CaptureParams(); previewMode = false; setPreviewMode(true); } public void openDriver() { - if (camera == null) { - camera = CameraDevice.open(); - } + // TODO switch back to CameraDevice later + // if (camera == null) { + // camera = CameraDevice.open(); + // } + // end TODO } public void closeDriver() { - if (camera != null) { - camera.close(); - camera = null; - } + // TODO switch back to CameraDevice later + // if (camera != null) { + // camera.close(); + // camera = null; + // } + // end TODO } public void capturePreview(Canvas canvas) { setPreviewMode(true); - camera.capture(canvas); + // TODO switch back to CameraDevice later + // camera.capture(canvas); + cameraSource.capture(canvas); + // end TODO } public Bitmap captureStill() { setPreviewMode(false); Canvas canvas = new Canvas(bitmap); - camera.capture(canvas); + // TODO switch back to CameraDevice later + // camera.capture(canvas); + cameraSource.capture(canvas); + // end TODO return bitmap; } @@ -124,8 +147,7 @@ final class CameraManager { } /** - * Images for the live preview are taken at low resolution in RGB. The final stills for the - * decoding step are taken in YUV, since we only need the luminance channel. Other code depends + * Images for the live preview are taken at low resolution in RGB. Other code depends * on the ability to call this method for free if the correct mode is already set. * * @param on Setting on true will engage preview mode, setting it false will request still mode. @@ -164,7 +186,9 @@ final class CameraManager { " srcHeight " + params.srcHeight + " leftPixel " + params.leftPixel + " topPixel " + params.topPixel + " outputWidth " + params.outputWidth + " outputHeight " + params.outputHeight); - camera.setCaptureParams(params); + // TODO switch back to CameraDevice later + // camera.setCaptureParams(params); + // end TODO previewMode = on; } } @@ -231,7 +255,7 @@ final class CameraManager { // Temporary: the minimum focus distance in inches. private static float getMinimumFocusDistance() { - return 12.0f; + return 6.0f; } private Point getScreenResolution() { diff --git a/android/src/com/google/zxing/client/android/CameraSurfaceView.java b/android/src/com/google/zxing/client/android/CameraSurfaceView.java index 0ab8d2b71..569dd3096 100644 --- a/android/src/com/google/zxing/client/android/CameraSurfaceView.java +++ b/android/src/com/google/zxing/client/android/CameraSurfaceView.java @@ -45,19 +45,14 @@ final class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callb // Install a SurfaceHolder.Callback so we get notified when the underlying surface is created // and destroyed. surfaceHolder = getHolder(); - surfaceHolder.setCallback(this); + surfaceHolder.addCallback(this); hasSurface = false; scannerAlpha = 0; surfaceHolder.setSizeFromLayout(); } - public boolean surfaceCreated(SurfaceHolder holder) { + public void surfaceCreated(SurfaceHolder holder) { hasSurface = true; - - // Tell the system that we filled the surface in this call. This is a lie to prevent the system - // from filling the surface for us automatically. THIS IS REQUIRED because otherwise we'll - // access the Surface object from 2 different threads which is not allowed. - return true; } public void surfaceDestroyed(SurfaceHolder holder) { @@ -150,6 +145,6 @@ final class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callb surfaceHolder.unlockCanvasAndPost(canvas); } - } + } } diff --git a/android/src/com/google/zxing/client/android/ResultHandler.java b/android/src/com/google/zxing/client/android/ResultHandler.java index cfe4df607..190cb73e2 100755 --- a/android/src/com/google/zxing/client/android/ResultHandler.java +++ b/android/src/com/google/zxing/client/android/ResultHandler.java @@ -16,10 +16,9 @@ package com.google.zxing.client.android; +import android.content.DialogInterface; import android.content.Intent; -import android.net.ContentURI; -import android.os.Handler; -import android.os.Message; +import android.net.Uri; import android.provider.Contacts; import com.google.zxing.client.result.AddressBookAUParsedResult; import com.google.zxing.client.result.AddressBookDoCoMoParsedResult; @@ -34,8 +33,6 @@ import com.google.zxing.client.result.UPCParsedResult; import com.google.zxing.client.result.URIParsedResult; import com.google.zxing.client.result.URLTOParsedResult; -import java.net.URISyntaxException; - /** * Handles the result of barcode decoding in the context of the Android platform, * by dispatching the proper intents and so on. @@ -43,7 +40,7 @@ import java.net.URISyntaxException; * @author srowen@google.com (Sean Owen) * @author dswitkin@google.com (Daniel Switkin) */ -final class ResultHandler extends Handler { +final class ResultHandler implements DialogInterface.OnClickListener { private final Intent intent; private final BarcodeReaderCaptureActivity captureActivity; @@ -74,63 +71,38 @@ final class ResultHandler extends Handler { putExtra(intent, Contacts.Intents.Insert.POSTAL, addressResult.getAddress()); } else if (type.equals(ParsedReaderResultType.BOOKMARK)) { // For now, we can only open the browser, and not actually add a bookmark - try { - intent = new Intent(Intent.VIEW_ACTION, new ContentURI(((BookmarkDoCoMoParsedResult) result).getURI())); - } catch (URISyntaxException e) { - } + intent = new Intent(Intent.VIEW_ACTION, Uri.parse(((BookmarkDoCoMoParsedResult) result).getURI())); } else if (type.equals(ParsedReaderResultType.URLTO)) { - try { - intent = new Intent(Intent.VIEW_ACTION, new ContentURI(((URLTOParsedResult) result).getURI())); - } catch (URISyntaxException e) { - } + intent = new Intent(Intent.VIEW_ACTION, Uri.parse(((URLTOParsedResult) result).getURI())); } else if (type.equals(ParsedReaderResultType.EMAIL)) { EmailDoCoMoParsedResult emailResult = (EmailDoCoMoParsedResult) result; - try { - intent = new Intent(Intent.SENDTO_ACTION, new ContentURI(emailResult.getTo())); - } catch (URISyntaxException e) { - } + intent = new Intent(Intent.SENDTO_ACTION, Uri.parse(emailResult.getTo())); putExtra(intent, "subject", emailResult.getSubject()); putExtra(intent, "body", emailResult.getBody()); } else if (type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) { EmailAddressParsedResult emailResult = (EmailAddressParsedResult) result; - try { - intent = new Intent(Intent.SENDTO_ACTION, new ContentURI(emailResult.getEmailAddress())); - } catch (URISyntaxException e) { - } + intent = new Intent(Intent.SENDTO_ACTION, Uri.parse(emailResult.getEmailAddress())); } else if (type.equals(ParsedReaderResultType.TEL)) { TelParsedResult telResult = (TelParsedResult) result; - try { - intent = new Intent(Intent.DIAL_ACTION, new ContentURI("tel:" + telResult.getNumber())); - } catch (URISyntaxException e) { - } + intent = new Intent(Intent.DIAL_ACTION, Uri.parse("tel:" + telResult.getNumber())); } else if (type.equals(ParsedReaderResultType.GEO)) { GeoParsedResult geoResult = (GeoParsedResult) result; - try { - intent = new Intent(Intent.VIEW_ACTION, new ContentURI(geoResult.getGeoURI())); - } catch (URISyntaxException e) { - } + intent = new Intent(Intent.VIEW_ACTION, Uri.parse(geoResult.getGeoURI())); } else if (type.equals(ParsedReaderResultType.UPC)) { UPCParsedResult upcResult = (UPCParsedResult) result; - try { - ContentURI uri = new ContentURI("http://www.upcdatabase.com/item.asp?upc=" + upcResult.getUPC()); - intent = new Intent(Intent.VIEW_ACTION, uri); - } catch (URISyntaxException e) { - } + Uri uri = Uri.parse("http://www.upcdatabase.com/item.asp?upc=" + upcResult.getUPC()); + intent = new Intent(Intent.VIEW_ACTION, uri); } else if (type.equals(ParsedReaderResultType.URI)) { URIParsedResult uriResult = (URIParsedResult) result; - try { - intent = new Intent(Intent.VIEW_ACTION, new ContentURI(uriResult.getURI())); - } catch (URISyntaxException e) { - } + intent = new Intent(Intent.VIEW_ACTION, Uri.parse(uriResult.getURI())); } else if (type.equals(ParsedReaderResultType.ANDROID_INTENT)) { intent = ((AndroidIntentParsedResult) result).getIntent(); } return intent; } - @Override - public void handleMessage(Message message) { - if (message.what == R.string.button_yes) { + public void onClick(DialogInterface dialogInterface, int i) { + if (i == DialogInterface.BUTTON1) { if (intent != null) { captureActivity.startActivity(intent); } diff --git a/android/src/com/tomgibara/android/camera/BitmapCamera.java b/android/src/com/tomgibara/android/camera/BitmapCamera.java new file mode 100644 index 000000000..0d8cba809 --- /dev/null +++ b/android/src/com/tomgibara/android/camera/BitmapCamera.java @@ -0,0 +1,63 @@ +package com.tomgibara.android.camera; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; + +// This is public-domain code generously supplied to the developer community +// by Tom Gibara, at http://www.tomgibara.com/android/camera-source + +/** + * A CameraSource implementation that repeatedly captures a single bitmap. + * + * @author Tom + * + */ + +public class BitmapCamera implements CameraSource { + + private final Bitmap bitmap; + private final Rect bounds; + private final Paint paint = new Paint(); + + public BitmapCamera(Bitmap bitmap, int width, int height) { + this.bitmap = bitmap; + bounds = new Rect(0, 0, width, height); + + paint.setFilterBitmap(true); + paint.setAntiAlias(true); + } + + @Override + public int getWidth() { + return bounds.right; + } + + @Override + public int getHeight() { + return bounds.bottom; + } + + @Override + public boolean open() { + return true; + } + + @Override + public boolean capture(Canvas canvas) { + if ( + bounds.right == bitmap.width() && + bounds.bottom == bitmap.height()) { + canvas.drawBitmap(bitmap, 0, 0, null); + } else { + canvas.drawBitmap(bitmap, null, bounds, paint); + } + return true; + } + + @Override + public void close() { + /* nothing to do */ + } +} diff --git a/android/src/com/tomgibara/android/camera/CameraSource.java b/android/src/com/tomgibara/android/camera/CameraSource.java new file mode 100644 index 000000000..0bd656ff7 --- /dev/null +++ b/android/src/com/tomgibara/android/camera/CameraSource.java @@ -0,0 +1,64 @@ +package com.tomgibara.android.camera; + +import android.graphics.Canvas; + +// This is public-domain code generously supplied to the developer community +// by Tom Gibara, at http://www.tomgibara.com/android/camera-source + +/** + * Provides a simple abstraction for obtaining preview captures from a camera + * on the Android platform. This interface intended to be used temporarily while + * the Google Android SDK fails to support camera capture from desktop devices + * (webcams etc). + * + * @author Tom Gibara + */ + +public interface CameraSource { + + static final String LOG_TAG = "camera"; + + /** + * Open the camera source for subsequent use via calls to capture(). + * + * @return true if the camera source was successfully opened. + */ + + boolean open(); + + /** + * Close the camera source. Calling close on a closed CameraSource is + * permitted but has no effect. The camera source may be reopened after + * being closed. + */ + + void close(); + + /** + * The width of the captured image. + * + * @return the width of the capture in pixels + */ + + int getWidth(); + + /** + * The height of the captured image. + * + * @return the height of the capture in pixels + */ + + int getHeight(); + + /** + * Attempts to render the current camera view onto the supplied canvas. + * The capture will be rendered into the rectangle (0,0,width,height). + * Outstanding transformations on the canvas may alter this. + * + * @param canvas the canvas to which the captured pixel data will be written + * @return true iff a frame was successfully written to the canvas + */ + + boolean capture(Canvas canvas); + +} diff --git a/android/src/com/tomgibara/android/camera/README b/android/src/com/tomgibara/android/camera/README new file mode 100644 index 000000000..cd8281e73 --- /dev/null +++ b/android/src/com/tomgibara/android/camera/README @@ -0,0 +1,2 @@ +This is public-domain code generously supplied to the developer community +by Tom Gibara, at http://www.tomgibara.com/android/camera-source \ No newline at end of file