--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2008 ZXing authors
+
+ 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.androidtest">
+ <application android:label="@string/app_name"
+ android:icon="@drawable/icon">
+ <activity android:name="ZXingTestActivity"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <activity android:name="CameraTestActivity"
+ android:screenOrientation="landscape">
+ </activity>
+ </application>
+ <uses-permission android:name="android.permission.CAMERA"/>
+</manifest>
--- /dev/null
+<?xml version="1.0" ?>
+<!--
+Copyright (C) 2008 ZXing authors
+
+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.
+-->
+<project name="ZXingTest" default="debug">
+ <!-- SDK Locations -->
+ <property file="../build.properties"/>
+ <property name="sdk-folder" value="${android-home}"/>
+ <property name="android-tools" value="${sdk-folder}/tools"/>
+
+ <!-- Application Package Name -->
+ <property name="application-package" value="com.google.zxing.client.androidtest" />
+
+ <!-- The intermediates directory -->
+ <!-- Eclipse uses "bin" for its own output, so we do the same. -->
+ <property name="outdir" value="bin" />
+
+ <!-- ************************************************************************************* -->
+ <!-- No user servicable parts below. -->
+
+ <property name="android-framework" value="${android-tools}/lib/framework.aidl" />
+
+ <!-- Input directories -->
+ <property name="resource-dir" value="res" />
+ <property name="asset-dir" value="assets" />
+ <property name="srcdir" value="src" />
+ <condition property="srcdir-ospath"
+ value="${basedir}\${srcdir}"
+ else="${basedir}/${srcdir}" >
+ <os family="windows"/>
+ </condition>
+
+ <property name="external-libs" value="../core" />
+ <condition property="external-libs-ospath"
+ value="${basedir}\${external-libs}"
+ else="${basedir}/${external-libs}" >
+ <os family="windows"/>
+ </condition>
+
+ <!-- Output directories -->
+ <property name="outdir-classes" value="${outdir}/classes" />
+ <condition property="outdir-classes-ospath"
+ value="${basedir}\${outdir-classes}"
+ else="${basedir}/${outdir-classes}" >
+ <os family="windows"/>
+ </condition>
+
+ <!-- Create R.java in the source directory -->
+ <property name="outdir-r" value="src" />
+
+ <!-- Intermediate files -->
+ <property name="dex-file" value="classes.dex" />
+ <property name="intermediate-dex" value="${outdir}/${dex-file}" />
+ <condition property="intermediate-dex-ospath"
+ value="${basedir}\${intermediate-dex}"
+ else="${basedir}/${intermediate-dex}" >
+ <os family="windows"/>
+ </condition>
+
+ <!-- The final package file to generate -->
+ <property name="resources-package" value="${outdir}/${ant.project.name}.ap_" />
+ <condition property="resources-package-ospath"
+ value="${basedir}\${resources-package}"
+ else="${basedir}/${resources-package}" >
+ <os family="windows"/>
+ </condition>
+
+ <property name="out-debug-package" value="${outdir}/${ant.project.name}-debug.apk" />
+ <condition property="out-debug-package-ospath"
+ value="${basedir}\${out-debug-package}"
+ else="${basedir}/${out-debug-package}" >
+ <os family="windows"/>
+ </condition>
+
+ <property name="out-unsigned-package" value="${outdir}/${ant.project.name}-unsigned.apk" />
+ <condition property="out-unsigned-package-ospath"
+ value="${basedir}\${out-unsigned-package}"
+ else="${basedir}/${out-unsigned-package}" >
+ <os family="windows"/>
+ </condition>
+
+ <!-- Tools -->
+ <condition property="aapt" value="${android-tools}/aapt.exe" else="${android-tools}/aapt" >
+ <os family="windows"/>
+ </condition>
+ <condition property="aidl" value="${android-tools}/aidl.exe" else="${android-tools}/aidl" >
+ <os family="windows"/>
+ </condition>
+ <condition property="adb" value="${android-tools}/adb.exe" else="${android-tools}/adb" >
+ <os family="windows"/>
+ </condition>
+ <condition property="dx" value="${android-tools}/dx.bat" else="${android-tools}/dx" >
+ <os family="windows"/>
+ </condition>
+ <condition property="apk-builder" value="${android-tools}/apkbuilder.bat" else="${android-tools}/apkbuilder" >
+ <os family="windows"/>
+ </condition>
+
+ <property name="android-jar" value="${sdk-folder}/android.jar" />
+
+ <!-- Rules -->
+
+ <!-- Create the output directories if they don't exist yet. -->
+ <target name="dirs">
+ <echo>Creating output directories if needed...</echo>
+ <mkdir dir="${outdir}" />
+ <mkdir dir="${outdir-classes}" />
+ </target>
+
+ <!-- Generate the R.java file for this project's resources. -->
+ <target name="resource-src" depends="dirs">
+ <echo>Generating R.java / Manifest.java from the resources...</echo>
+ <exec executable="${aapt}" failonerror="true">
+ <arg value="package" />
+ <arg value="-m" />
+ <arg value="-J" />
+ <arg value="${outdir-r}" />
+ <arg value="-M" />
+ <arg value="AndroidManifest.xml" />
+ <arg value="-S" />
+ <arg value="${resource-dir}" />
+ <arg value="-I" />
+ <arg value="${android-jar}" />
+ </exec>
+ </target>
+
+ <!-- Generate java classes from .aidl files. -->
+ <target name="aidl" depends="dirs">
+ <echo>Compiling aidl files into Java classes...</echo>
+ <apply executable="${aidl}" failonerror="true">
+ <arg value="-p${android-framework}" />
+ <arg value="-I${srcdir}" />
+ <fileset dir="${srcdir}">
+ <include name="**/*.aidl"/>
+ </fileset>
+ </apply>
+ </target>
+
+ <!-- Compile this project's .java files into .class files. -->
+ <target name="compile" depends="dirs, resource-src, aidl">
+ <javac encoding="ascii" target="1.5" debug="true" extdirs=""
+ srcdir="."
+ destdir="${outdir-classes}"
+ bootclasspath="${android-jar}">
+ <classpath>
+ <fileset dir="${external-libs}" includes="*.jar"/>
+ </classpath>
+ </javac>
+ </target>
+
+ <!-- Convert this project's .class files into .dex files. -->
+ <target name="dex" depends="compile">
+ <echo>Converting compiled files and external libraries into ${outdir}/${dex-file}...</echo>
+ <apply executable="${dx}" failonerror="true" parallel="true">
+ <arg value="--dex" />
+ <arg value="--output=${intermediate-dex-ospath}" />
+ <arg path="${outdir-classes-ospath}" />
+ <fileset dir="${external-libs}" includes="*.jar"/>
+ </apply>
+ </target>
+
+ <!-- Put the project's resources into the output package file. -->
+ <target name="package-res-and-assets">
+ <echo>Packaging resources and assets...</echo>
+ <exec executable="${aapt}" failonerror="true">
+ <arg value="package" />
+ <arg value="-f" />
+ <arg value="-M" />
+ <arg value="AndroidManifest.xml" />
+ <arg value="-S" />
+ <arg value="${resource-dir}" />
+ <arg value="-A" />
+ <arg value="${asset-dir}" />
+ <arg value="-I" />
+ <arg value="${android-jar}" />
+ <arg value="-F" />
+ <arg value="${resources-package}" />
+ </exec>
+ </target>
+
+ <!-- Same as package-res-and-assets, but without "-A ${asset-dir}" -->
+ <target name="package-res-no-assets">
+ <echo>Packaging resources...</echo>
+ <exec executable="${aapt}" failonerror="true">
+ <arg value="package" />
+ <arg value="-f" />
+ <arg value="-M" />
+ <arg value="AndroidManifest.xml" />
+ <arg value="-S" />
+ <arg value="${resource-dir}" />
+ <!-- No assets directory -->
+ <arg value="-I" />
+ <arg value="${android-jar}" />
+ <arg value="-F" />
+ <arg value="${resources-package}" />
+ </exec>
+ </target>
+
+ <!-- Invoke the proper target depending on whether or not
+an assets directory is present. -->
+ <!-- TODO: find a nicer way to include the "-A ${asset-dir}" argument
+only when the assets dir exists. -->
+ <target name="package-res">
+ <available file="${asset-dir}" type="dir"
+ property="res-target" value="and-assets" />
+ <property name="res-target" value="no-assets" />
+ <antcall target="package-res-${res-target}" />
+ </target>
+
+ <!-- Package the application and sign it with a debug key.
+ This is the default target when building. It is used for debug. -->
+ <target name="debug" depends="dex, package-res">
+ <echo>Packaging ${out-debug-package}, and signing it with a debug key...</echo>
+ <exec executable="${apk-builder}" failonerror="true">
+ <arg value="${out-debug-package-ospath}" />
+ <arg value="-z" />
+ <arg value="${resources-package-ospath}" />
+ <arg value="-f" />
+ <arg value="${intermediate-dex-ospath}" />
+ <arg value="-rf" />
+ <arg value="${srcdir-ospath}" />
+ <arg value="-rj" />
+ <arg value="${external-libs-ospath}" />
+ </exec>
+ </target>
+
+ <!-- Package the application without signing it.
+ This allows for the application to be signed later with an official publishing key. -->
+ <target name="release" depends="dex, package-res">
+ <echo>Packaging ${out-unsigned-package} for release...</echo>
+ <exec executable="${apk-builder}" failonerror="true">
+ <arg value="${out-unsigned-package-ospath}" />
+ <arg value="-u" />
+ <arg value="-z" />
+ <arg value="${resources-package-ospath}" />
+ <arg value="-f" />
+ <arg value="${intermediate-dex-ospath}" />
+ <arg value="-rf" />
+ <arg value="${srcdir-ospath}" />
+ <arg value="-rj" />
+ <arg value="${external-libs-ospath}" />
+ </exec>
+ <echo>It will need to be signed with jarsigner before being published.</echo>
+ </target>
+
+ <!-- Install the package on the default emulator -->
+ <target name="install" depends="debug">
+ <echo>Installing ${out-debug-package} onto default emulator...</echo>
+ <exec executable="${adb}" failonerror="true">
+ <arg value="install" />
+ <arg value="${out-debug-package}" />
+ </exec>
+ </target>
+
+ <target name="reinstall" depends="debug">
+ <echo>Installing ${out-debug-package} onto default emulator...</echo>
+ <exec executable="${adb}" failonerror="true">
+ <arg value="install" />
+ <arg value="-r" />
+ <arg value="${out-debug-package}" />
+ </exec>
+ </target>
+
+ <!-- Uinstall the package from the default emulator -->
+ <target name="uninstall">
+ <echo>Uninstalling ${application-package} from the default emulator...</echo>
+ <exec executable="${adb}" failonerror="true">
+ <arg value="uninstall" />
+ <arg value="${application-package}" />
+ </exec>
+ </target>
+
+ <target name="clean">
+ <delete dir="${outdir}"/>
+ </target>
+
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2008 ZXing authors
+
+ 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.
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <SurfaceView android:id="@+id/preview_view"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_centerInParent="true"/>
+
+ <com.google.zxing.client.androidtest.ViewfinderView
+ android:id="@+id/viewfinder_view"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/transparent"/>
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/transparent">
+
+ <FrameLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:background="@color/transparent"/>
+
+ <FrameLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:background="@color/status_view"
+ android:baselineAligned="false"
+ android:padding="4px">
+
+ <TextView android:id="@+id/status_text_view"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left|center_vertical"
+ android:text="@string/status_message"
+ android:textColor="@color/status_text"/>
+
+ </FrameLayout>
+
+ </LinearLayout>
+
+</FrameLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2008 ZXing authors
+
+ 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.
+ -->
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center_horizontal"
+ android:padding="10px">
+ <TableRow>
+ <Button android:id="@+id/scan_product"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/scan_product"/>
+ <Button android:id="@+id/scan_qr_code"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/scan_qr_code"/>
+ </TableRow>
+ <TableRow>
+ <Button android:id="@+id/test_camera"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/test_camera"/>
+ <Button android:id="@+id/search_book_contents"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/search_book_contents"/>
+ </TableRow>
+ <TableRow>
+ <Button android:id="@+id/encode_url"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/encode_url"/>
+ <Button android:id="@+id/encode_email"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/encode_email"/>
+ </TableRow>
+ <TableRow>
+ <Button android:id="@+id/encode_phone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/encode_phone"/>
+ <Button android:id="@+id/encode_sms"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/encode_sms"/>
+ </TableRow>
+ <TableRow>
+ <Button android:id="@+id/encode_contact"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/encode_contact"/>
+ <Button android:id="@+id/encode_location"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/encode_location"/>
+ </TableRow>
+ <TableRow>
+ <Button android:id="@+id/encode_bad_data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/encode_bad_data"/>
+ </TableRow>
+</TableLayout>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2008 ZXing authors
+
+ 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.
+ -->
+<resources>
+ <declare-styleable name="ViewfinderView">
+ </declare-styleable>
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2008 ZXing authors
+
+ 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.
+ -->
+<resources>
+ <color name="status_view">#50000000</color>
+ <color name="status_text">#ffffffff</color>
+ <color name="transparent">#00000000</color>
+ <color name="viewfinder_frame">#ffffffff</color>
+ <color name="viewfinder_mask">#ccff0000</color>
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2008 ZXing authors
+
+ 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.
+ -->
+<resources>
+ <!-- Messages IDs -->
+ <item type="id" name="auto_focus"/>
+ <item type="id" name="quit"/>
+ <item type="id" name="save"/>
+ <item type="id" name="save_succeeded"/>
+ <item type="id" name="save_failed"/>
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2008 ZXing authors
+
+ 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.
+ -->
+<resources>
+ <string name="app_name">ZXing Test</string>
+ <string name="scan_product">Scan product</string>
+ <string name="scan_qr_code">Scan QR Code</string>
+ <string name="search_book_contents">Search Book Contents</string>
+ <string name="test_camera">Test camera</string>
+ <string name="encode_url">Encode URL</string>
+ <string name="encode_email">Encode email</string>
+ <string name="encode_phone">Encode phone</string>
+ <string name="encode_sms">Encode SMS</string>
+ <string name="encode_contact">Encode contact</string>
+ <string name="encode_location">Encode location</string>
+ <string name="encode_bad_data">Encode bad data</string>
+ <string name="result_failed">No barcode found</string>
+ <string name="result_failed_why">"The user gave up and pressed Back"</string>
+ <string name="result_succeeded">Found barcode</string>
+ <string name="status_message">Press the shutter button to save images to the SD card for testing purposes. Press DPAD_CENTER to trigger autofocus.</string>
+ <string name="save_succeeded">Save succeeded</string>
+ <string name="save_failed">Save failed - is the SD card installed?</string>
+</resources>
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.
+ */
+
+package com.google.zxing.client.androidtest;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Message;
+import android.view.Display;
+import android.view.SurfaceHolder;
+import android.view.WindowManager;
+
+/**
+ * This object wraps the Camera service object and expects to be the only one talking to it. The
+ * implementation encapsulates the steps needed to take preview-sized images, which are used for
+ * both preview and decoding.
+ */
+final class CameraManager {
+
+ private static final String TAG = "CameraManager";
+
+ private static CameraManager mCameraManager;
+ private Camera mCamera;
+ private final Context mContext;
+ private Point mScreenResolution;
+ private Rect mFramingRect;
+ private Handler mPreviewHandler;
+ private int mPreviewMessage;
+ private Handler mAutoFocusHandler;
+ private int mAutoFocusMessage;
+ private boolean mPreviewing;
+
+ public static void init(Context context) {
+ if (mCameraManager == null) {
+ mCameraManager = new CameraManager(context);
+ mCameraManager.getScreenResolution();
+ }
+ }
+
+ public static CameraManager get() {
+ return mCameraManager;
+ }
+
+ private CameraManager(Context context) {
+ mContext = context;
+ mCamera = null;
+ mPreviewing = false;
+ }
+
+ public void openDriver(SurfaceHolder holder) {
+ if (mCamera == null) {
+ mCamera = Camera.open();
+ mCamera.setPreviewDisplay(holder);
+
+ setCameraParameters();
+ }
+ }
+
+ public void closeDriver() {
+ if (mCamera != null) {
+ mCamera.release();
+ mCamera = null;
+ }
+ }
+
+ public void startPreview() {
+ if (mCamera != null && !mPreviewing) {
+ mCamera.startPreview();
+ mPreviewing = true;
+ }
+ }
+
+ public void stopPreview() {
+ if (mCamera != null && mPreviewing) {
+ mCamera.setPreviewCallback(null);
+ mCamera.stopPreview();
+ mPreviewHandler = null;
+ mAutoFocusHandler = null;
+ mPreviewing = false;
+ }
+ }
+
+ /**
+ * A single preview frame will be returned to the handler supplied. The data will arrive as
+ * byte[] in the message.obj field, with width and height encoded as message.arg1 and
+ * message.arg2, respectively.
+ *
+ * @param handler The handler to send the message to.
+ * @param message The what field of the message to be sent.
+ */
+ public void requestPreviewFrame(Handler handler, int message) {
+ if (mCamera != null && mPreviewing) {
+ mPreviewHandler = handler;
+ mPreviewMessage = message;
+ mCamera.setPreviewCallback(previewCallback);
+ }
+ }
+
+ public void requestAutoFocus(Handler handler, int message) {
+ if (mCamera != null && mPreviewing) {
+ mAutoFocusHandler = handler;
+ mAutoFocusMessage = message;
+ mCamera.autoFocus(autoFocusCallback);
+ }
+ }
+
+ /**
+ * Calculates the framing rect which the UI should draw to show the user where to place the
+ * barcode. The actual captured image should be a bit larger than indicated because they might
+ * frame the shot too tightly. This target helps with alignment as well as forces the user to
+ * hold the device far enough away to ensure the image will be in focus.
+ *
+ * @return The rectangle to draw on screen in window coordinates.
+ */
+ public Rect getFramingRect() {
+ if (mFramingRect == null) {
+ int size = ((mScreenResolution.x < mScreenResolution.y) ? mScreenResolution.x :
+ mScreenResolution.y) * 3 / 4;
+ int leftOffset = (mScreenResolution.x - size) / 2;
+ int topOffset = (mScreenResolution.y - size) / 2;
+ mFramingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size);
+ }
+ return mFramingRect;
+ }
+
+ /**
+ * Preview frames are delivered here, which we pass on to the registered handler. Make sure to
+ * clear the handler so it will only receive one message.
+ */
+ private final Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
+ public void onPreviewFrame(byte[] data, Camera camera) {
+ camera.setPreviewCallback(null);
+ if (mPreviewHandler != null) {
+ Message message = mPreviewHandler.obtainMessage(mPreviewMessage,
+ mScreenResolution.x, mScreenResolution.y, data);
+ message.sendToTarget();
+ mPreviewHandler = null;
+ }
+ }
+ };
+
+ private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
+ public void onAutoFocus(boolean success, Camera camera) {
+ if (mAutoFocusHandler != null) {
+ Message message = mAutoFocusHandler.obtainMessage(mAutoFocusMessage, success);
+ // The Barcodes app needs to insert a delay here because it does continuous focus,
+ // but this test app does not, so send the message immediately.
+ message.sendToTarget();
+ mAutoFocusHandler = null;
+ }
+ }
+ };
+
+ /**
+ * Sets the camera up to take preview images which are used for both preview and decoding. We're
+ * counting on the default YUV420 semi-planar data. If that changes in the future, we'll need to
+ * specify it explicitly with setPreviewFormat().
+ */
+ private void setCameraParameters() {
+ Camera.Parameters parameters = mCamera.getParameters();
+ parameters.setPreviewSize(mScreenResolution.x, mScreenResolution.y);
+ mCamera.setParameters(parameters);
+ }
+
+ private Point getScreenResolution() {
+ if (mScreenResolution == null) {
+ WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ Display display = wm.getDefaultDisplay();
+ mScreenResolution = new Point(display.getWidth(), display.getHeight());
+ }
+ return mScreenResolution;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.
+ */
+
+package com.google.zxing.client.androidtest;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.KeyEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+public final class CameraTestActivity extends Activity implements SurfaceHolder.Callback {
+
+ private SaveThread mSaveThread;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ Window window = getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ setContentView(R.layout.camera_test);
+
+ CameraManager.init(getApplication());
+
+ SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
+ SurfaceHolder surfaceHolder = surfaceView.getHolder();
+ surfaceHolder.addCallback(this);
+ surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (mSaveThread == null) {
+ mSaveThread = new SaveThread(this, CameraManager.get().getFramingRect());
+ mSaveThread.start();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ CameraManager.get().stopPreview();
+ if (mSaveThread != null) {
+ Message quit = Message.obtain(mSaveThread.mHandler, R.id.quit);
+ quit.sendToTarget();
+ try {
+ mSaveThread.join();
+ } catch (InterruptedException e) {
+ }
+ mSaveThread = null;
+ }
+ CameraManager.get().closeDriver();
+ }
+
+ public Handler mHandler = new Handler() {
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case R.id.auto_focus:
+ // Do not continuously auto focus
+ break;
+ case R.id.save_succeeded: {
+ Toast.makeText(CameraTestActivity.this, R.string.save_succeeded, 500).show();
+ break;
+ }
+ case R.id.save_failed: {
+ Toast.makeText(CameraTestActivity.this, R.string.save_failed, 2000).show();
+ break;
+ }
+ }
+ }
+ };
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
+ if (event.getRepeatCount() == 0) {
+ CameraManager.get().requestAutoFocus(mHandler, R.id.auto_focus);
+ }
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_CAMERA) {
+ if (event.getRepeatCount() == 0) {
+ CameraManager.get().requestPreviewFrame(mSaveThread.mHandler, R.id.save);
+ }
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ public void surfaceCreated(SurfaceHolder holder) {
+ CameraManager.get().openDriver(holder);
+ CameraManager.get().startPreview();
+ }
+
+ public void surfaceDestroyed(SurfaceHolder holder) {
+
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.
+ */
+
+package com.google.zxing.client.androidtest;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+
+final class SaveThread extends Thread {
+
+ private static final String TAG = "SaveThread";
+
+ public Handler mHandler;
+
+ private CameraTestActivity mActivity;
+ private Rect mFramingRect;
+
+ SaveThread(CameraTestActivity activity, Rect framingRect) {
+ mActivity = activity;
+ mFramingRect = framingRect;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ mHandler = new Handler() {
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case R.id.save:
+ save((byte[]) message.obj, message.arg1, message.arg2);
+ break;
+ case R.id.quit:
+ Looper.myLooper().quit();
+ break;
+ }
+ }
+ };
+ Looper.loop();
+ }
+
+ // Save the center rectangle of the Y channel as a greyscale JPEG to the SD card
+ private void save(byte[] data, int width, int height) {
+ int framingWidth = mFramingRect.width();
+ int framingHeight = mFramingRect.height();
+ assert (framingWidth <= width);
+ assert (framingHeight <= height);
+
+ int leftOffset = mFramingRect.left;
+ int topOffset = mFramingRect.top;
+ int[] colors = new int[framingWidth * framingHeight];
+
+ for (int y = 0; y < framingHeight; y++) {
+ int rowOffset = (y + topOffset) * width + leftOffset;
+ for (int x = 0; x < framingWidth; x++) {
+ int pixel = (int) data[rowOffset + x];
+ pixel = 0xff000000 + (pixel << 16) + (pixel << 8) + pixel;
+ colors[y * framingWidth + x] = pixel;
+ }
+ }
+
+ Bitmap bitmap = Bitmap.createBitmap(colors, framingWidth, framingHeight,
+ Bitmap.Config.ARGB_8888);
+ OutputStream outStream = getNewPhotoOutputStream();
+ if (outStream != null) {
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outStream);
+ try {
+ outStream.close();
+ Message message = Message.obtain(mActivity.mHandler, R.id.save_succeeded);
+ message.sendToTarget();
+ return;
+ } catch (IOException e) {
+ Log.e(TAG, "Exception closing stream: " + e.toString());
+ }
+ }
+
+ Message message = Message.obtain(mActivity.mHandler, R.id.save_failed);
+ message.sendToTarget();
+ }
+
+ private OutputStream getNewPhotoOutputStream() {
+ File sdcard = new File("/sdcard");
+ if (sdcard.exists()) {
+ File barcodes = new File(sdcard, "barcodes");
+ if (barcodes.exists()) {
+ if (!barcodes.isDirectory()) {
+ Log.e(TAG, "/sdcard/barcodes exists but is not a directory");
+ return null;
+ }
+ } else {
+ if (!barcodes.mkdir()) {
+ Log.e(TAG, "Could not create /sdcard/barcodes directory");
+ return null;
+ }
+ }
+ Date now = new Date();
+ String fileName = now.getTime() + ".jpg";
+ try {
+ return new FileOutputStream(new File(barcodes, fileName));
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "Could not create FileOutputStream");
+ }
+ } else {
+ Log.e(TAG, "/sdcard does not exist");
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.
+ */
+
+package com.google.zxing.client.androidtest;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class ViewfinderView extends View {
+
+ private Paint mPaint;
+ private Rect mBox;
+ private int mMaskColor;
+ private int mFrameColor;
+
+ // This constructor is used when the class is built from an XML resource.
+ public ViewfinderView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ // Initialize these once for performance rather than calling them every time in onDraw().
+ mPaint = new Paint();
+ mBox = new Rect();
+ Resources resources = getResources();
+ mMaskColor = resources.getColor(R.color.viewfinder_mask);
+ mFrameColor = resources.getColor(R.color.viewfinder_frame);
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ Rect frame = CameraManager.get().getFramingRect();
+ int width = canvas.getWidth();
+ int height = canvas.getHeight();
+
+ // Draw the exterior (i.e. outside the framing rect) darkened, in red to distinguish it from
+ // the regular barcodes app
+ mPaint.setColor(mMaskColor);
+ mBox.set(0, 0, width, frame.top);
+ canvas.drawRect(mBox, mPaint);
+ mBox.set(0, frame.top, frame.left, frame.bottom + 1);
+ canvas.drawRect(mBox, mPaint);
+ mBox.set(frame.right + 1, frame.top, width, frame.bottom + 1);
+ canvas.drawRect(mBox, mPaint);
+ mBox.set(0, frame.bottom + 1, width, height);
+ canvas.drawRect(mBox, mPaint);
+
+ // Draw a two pixel solid white border inside the framing rect
+ mPaint.setColor(mFrameColor);
+ mBox.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
+ canvas.drawRect(mBox, mPaint);
+ mBox.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
+ canvas.drawRect(mBox, mPaint);
+ mBox.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
+ canvas.drawRect(mBox, mPaint);
+ mBox.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
+ canvas.drawRect(mBox, mPaint);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * 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.
+ */
+
+package com.google.zxing.client.androidtest;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Contacts;
+import android.view.View;
+import android.widget.Button;
+
+public class ZXingTestActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.test);
+
+ Button scan_product = (Button) findViewById(R.id.scan_product);
+ scan_product.setOnClickListener(mScanProduct);
+
+ Button scan_qr_code = (Button) findViewById(R.id.scan_qr_code);
+ scan_qr_code.setOnClickListener(mScanQRCode);
+
+ Button test_camera = (Button) findViewById(R.id.test_camera);
+ test_camera.setOnClickListener(mTestCamera);
+
+ Button search_book_contents = (Button) findViewById(R.id.search_book_contents);
+ search_book_contents.setOnClickListener(mSearchBookContents);
+
+ Button encode_url = (Button) findViewById(R.id.encode_url);
+ encode_url.setOnClickListener(mEncodeURL);
+
+ Button encode_email = (Button) findViewById(R.id.encode_email);
+ encode_email.setOnClickListener(mEncodeEmail);
+
+ Button encode_phone = (Button) findViewById(R.id.encode_phone);
+ encode_phone.setOnClickListener(mEncodePhone);
+
+ Button encode_sms = (Button) findViewById(R.id.encode_sms);
+ encode_sms.setOnClickListener(mEncodeSMS);
+
+ Button encode_contact = (Button) findViewById(R.id.encode_contact);
+ encode_contact.setOnClickListener(mEncodeContact);
+
+ Button encode_location = (Button) findViewById(R.id.encode_location);
+ encode_location.setOnClickListener(mEncodeLocation);
+
+ Button encode_bad_data = (Button) findViewById(R.id.encode_bad_data);
+ encode_bad_data.setOnClickListener(mEncodeBadData);
+ }
+
+ public Button.OnClickListener mScanProduct = new Button.OnClickListener() {
+ public void onClick(View v) {
+ Intent intent = new Intent("com.google.zxing.client.android.SCAN");
+ intent.putExtra("SCAN_MODE", "PRODUCT_MODE");
+ startActivityForResult(intent, 0);
+ }
+ };
+
+ public Button.OnClickListener mScanQRCode = new Button.OnClickListener() {
+ public void onClick(View v) {
+ Intent intent = new Intent("com.google.zxing.client.android.SCAN");
+ intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
+ startActivityForResult(intent, 0);
+ }
+ };
+
+ public Button.OnClickListener mTestCamera = new Button.OnClickListener() {
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setClassName(ZXingTestActivity.this, CameraTestActivity.class.getName());
+ startActivity(intent);
+ }
+ };
+
+ public Button.OnClickListener mSearchBookContents = new Button.OnClickListener() {
+ public void onClick(View v) {
+ Intent intent = new Intent("com.google.zxing.client.android.SEARCH_BOOK_CONTENTS");
+ intent.putExtra("ISBN", "9780441014989");
+ intent.putExtra("QUERY", "future");
+ startActivity(intent);
+ }
+ };
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ if (requestCode == 0) {
+ if (resultCode == RESULT_OK) {
+ String contents = intent.getStringExtra("SCAN_RESULT");
+ String format = intent.getStringExtra("SCAN_RESULT_FORMAT");
+ showDialog(R.string.result_succeeded, "Format: " + format + "\nContents: " + contents);
+ } else if (resultCode == RESULT_CANCELED) {
+ showDialog(R.string.result_failed, getString(R.string.result_failed_why));
+ }
+ }
+ }
+
+ public Button.OnClickListener mEncodeURL = new Button.OnClickListener() {
+ public void onClick(View v) {
+ encodeBarcode("TEXT_TYPE", "http://www.nytimes.com");
+ }
+ };
+
+ public Button.OnClickListener mEncodeEmail = new Button.OnClickListener() {
+ public void onClick(View v) {
+ encodeBarcode("EMAIL_TYPE", "foo@example.com");
+ }
+ };
+
+ public Button.OnClickListener mEncodePhone = new Button.OnClickListener() {
+ public void onClick(View v) {
+ encodeBarcode("PHONE_TYPE", "2125551212");
+ }
+ };
+
+ public Button.OnClickListener mEncodeSMS = new Button.OnClickListener() {
+ public void onClick(View v) {
+ encodeBarcode("SMS_TYPE", "2125551212");
+ }
+ };
+
+ public Button.OnClickListener mEncodeContact = new Button.OnClickListener() {
+ public void onClick(View v) {
+ Bundle bundle = new Bundle();
+ bundle.putString(Contacts.Intents.Insert.NAME, "Jenny");
+ bundle.putString(Contacts.Intents.Insert.PHONE, "8675309");
+ bundle.putString(Contacts.Intents.Insert.EMAIL, "jenny@the80s.com");
+ encodeBarcode("CONTACT_TYPE", bundle);
+ }
+ };
+
+ public Button.OnClickListener mEncodeLocation = new Button.OnClickListener() {
+ public void onClick(View v) {
+ Bundle bundle = new Bundle();
+ bundle.putFloat("LAT", 40.829208f);
+ bundle.putFloat("LONG", -74.191279f);
+ encodeBarcode("LOCATION_TYPE", bundle);
+ }
+ };
+
+ public Button.OnClickListener mEncodeBadData = new Button.OnClickListener() {
+ public void onClick(View v) {
+ encodeBarcode(null, "bar");
+ }
+ };
+
+ private void showDialog(int title, String message) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(title);
+ builder.setMessage(message);
+ builder.setPositiveButton("OK", null);
+ builder.show();
+ }
+
+ private void encodeBarcode(String type, String data) {
+ Intent intent = new Intent("com.google.zxing.client.android.ENCODE");
+ intent.putExtra("ENCODE_TYPE", type);
+ intent.putExtra("ENCODE_DATA", data);
+ startActivity(intent);
+ }
+
+ private void encodeBarcode(String type, Bundle data) {
+ Intent intent = new Intent("com.google.zxing.client.android.ENCODE");
+ intent.putExtra("ENCODE_TYPE", type);
+ intent.putExtra("ENCODE_DATA", data);
+ startActivity(intent);
+ }
+
+}