summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>2008-03-28 19:54:29 +0300
committersrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>2008-03-28 19:54:29 +0300
commit414eca942699ef8b3d6e33e829a0c19ac053d093 (patch)
tree6dbc35cbdb4275ee917d79ed8c062cc41cc977e9
parent267bd51f5cf4be4be3fd5647871be4477312dc7d (diff)
downloadzxing-android-embedded-414eca942699ef8b3d6e33e829a0c19ac053d093.tar.xz
Updates to build on M5
git-svn-id: http://zxing.googlecode.com/svn/trunk/android@320 59b500cc-1b3d-0410-9834-0bbf25fbcc57
-rw-r--r--AndroidManifest.xml23
-rw-r--r--build.xml26
-rw-r--r--src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java62
-rw-r--r--src/com/google/zxing/client/android/CameraManager.java54
-rw-r--r--src/com/google/zxing/client/android/CameraSurfaceView.java11
-rwxr-xr-xsrc/com/google/zxing/client/android/ResultHandler.java56
-rw-r--r--src/com/tomgibara/android/camera/BitmapCamera.java63
-rw-r--r--src/com/tomgibara/android/camera/CameraSource.java64
-rw-r--r--src/com/tomgibara/android/camera/README2
9 files changed, 255 insertions, 106 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8f925eb8..3d614d8f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1,11 +1,26 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2008 Google Inc.
+
+ 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.
+ -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.zxing.client.android">
<application android:icon="@drawable/icon">
- <activity class=".BarcodeReaderCaptureActivity" android:label="@string/app_name">
+ <activity android:name=".BarcodeReaderCaptureActivity" android:label="@string/app_name">
<intent-filter>
- <action android:value="android.intent.action.MAIN"/>
- <category android:value="android.intent.category.LAUNCHER"/>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/build.xml b/build.xml
index 57b6d537..2400b132 100644
--- a/build.xml
+++ b/build.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" ?>
-
+<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2008 Google Inc.
@@ -22,6 +21,7 @@
<property file="../build.properties"/>
<property name="sdk-folder" value="${android-home}"/>
<property name="android-tools" value="${sdk-folder}/tools"/>
+ <property name="android-framework" value="${android-tools}/lib/framework.aidl"/>
<!-- The intermediates directory -->
<!-- Eclipse uses "bin" for its own output, so we do the same. -->
@@ -51,8 +51,9 @@
<property name="aapt" value="${android-tools}/aapt"/>
<property name="aidl" value="${android-tools}/aidl"/>
<property name="dx" value="${android-tools}/dx"/>
+ <property name="adb" value="${android-tools}/adb" />
+ <property name="android-jar" value="${sdk-folder}/android.jar" />
<property name="zip" value="zip"/>
- <property name="android-jar" value="${sdk-folder}/android.jar"/>
<!-- Rules -->
@@ -119,6 +120,8 @@
<!-- Generate java classes from .aidl files. -->
<target name="aidl" depends="dirs">
<apply executable="${aidl}" failonerror="true">
+ <arg value="-p${android-framework}"/>
+ <arg value="-I${srcdir}"/>
<fileset dir="${srcdir}">
<include name="**/*.aidl"/>
</fileset>
@@ -185,7 +188,7 @@
<arg value="--output=${intermediate-dex}"/>
<arg value="--locals=${locals}"/>
<arg value="--positions=${positions}"/>
- <arg path="${outdir-classes}"/>
+ <arg path="${basedir}/${outdir-classes}"/>
</exec>
</target>
@@ -245,7 +248,11 @@ only when the assets dir exists. -->
update="true"/>
</target>
- <!-- Put the project's .dex files into the output package file. -->
+ <!-- Put the project's .dex files into the output package file.
+ Use the "zip" command, available on most un*x/Linux/MacOS systems,
+ to create the new package (Ant 1.7 has an internal 'zip' command,
+ however Ant 1.6.5 lacks it and is still widely installed.)
+ -->
<target name="package-dex" depends="dex, package-res">
<echo>Packaging dex...</echo>
<exec executable="${zip}" failonerror="true">
@@ -258,6 +265,15 @@ only when the assets dir exists. -->
<!-- Create the package file for this project from the sources. -->
<target name="package" depends="package-dex"/>
+ <!-- Install package on the default emulator -->
+ <target name="install">
+ <echo>Sending package to default emulator...</echo>
+ <exec executable="${adb}" failonerror="true">
+ <arg value="install" />
+ <arg value="${out-package}" />
+ </exec>
+ </target>
+
<target name="clean">
<delete dir="${outdir}"/>
</target>
diff --git a/src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java b/src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java
index 31966552..a682c438 100644
--- a/src/com/google/zxing/client/android/BarcodeReaderCaptureActivity.java
+++ b/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);
@@ -70,14 +62,6 @@ public final class BarcodeReaderCaptureActivity extends Activity {
}
@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();
cameraManager.openDriver();
@@ -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/src/com/google/zxing/client/android/CameraManager.java b/src/com/google/zxing/client/android/CameraManager.java
index 0cd3782f..6bcf7487 100644
--- a/src/com/google/zxing/client/android/CameraManager.java
+++ b/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/src/com/google/zxing/client/android/CameraSurfaceView.java b/src/com/google/zxing/client/android/CameraSurfaceView.java
index 0ab8d2b7..569dd309 100644
--- a/src/com/google/zxing/client/android/CameraSurfaceView.java
+++ b/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/src/com/google/zxing/client/android/ResultHandler.java b/src/com/google/zxing/client/android/ResultHandler.java
index cfe4df60..190cb73e 100755
--- a/src/com/google/zxing/client/android/ResultHandler.java
+++ b/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/src/com/tomgibara/android/camera/BitmapCamera.java b/src/com/tomgibara/android/camera/BitmapCamera.java
new file mode 100644
index 00000000..0d8cba80
--- /dev/null
+++ b/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/src/com/tomgibara/android/camera/CameraSource.java b/src/com/tomgibara/android/camera/CameraSource.java
new file mode 100644
index 00000000..0bd656ff
--- /dev/null
+++ b/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/src/com/tomgibara/android/camera/README b/src/com/tomgibara/android/camera/README
new file mode 100644
index 00000000..cd8281e7
--- /dev/null
+++ b/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