mirror of
https://github.com/zxing/zxing.git
synced 2024-11-10 21:14:06 -08:00
Removing android-m3 since it is no longer in active development (but we have it in SVN of course)
git-svn-id: https://zxing.googlecode.com/svn/trunk@412 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
f431cae59f
commit
16f01d19bf
|
@ -1,14 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<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">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:value="android.intent.action.MAIN"/>
|
|
||||||
<category android:value="android.intent.category.LAUNCHER"/>
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
<uses-permission id="android.permission.READ_CONTACTS"/>
|
|
||||||
<uses-permission id="android.permission.WRITE_CONTACTS"/>
|
|
||||||
</manifest>
|
|
|
@ -1,274 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- This is a mildly hacked version of the auto-generated project
|
|
||||||
build.xml file. -->
|
|
||||||
<project name="BarcodeReaderM3" default="package">
|
|
||||||
<property file="../build.properties"/>
|
|
||||||
<property name="sdk-folder" value="${android-m3-home}"/>
|
|
||||||
<property name="android-tools" value="${sdk-folder}/tools"/>
|
|
||||||
|
|
||||||
<!-- 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. -->
|
|
||||||
|
|
||||||
<!-- Input directories -->
|
|
||||||
<property name="resource-dir" value="res"/>
|
|
||||||
<property name="asset-dir" value="assets"/>
|
|
||||||
<property name="srcdir" value="src"/>
|
|
||||||
|
|
||||||
<!-- Output directories -->
|
|
||||||
<property name="outdir-classes" value="${outdir}/classes"/>
|
|
||||||
|
|
||||||
<!-- 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" location="${outdir}/${dex-file}"/>
|
|
||||||
|
|
||||||
<!-- The final package file to generate -->
|
|
||||||
<property name="out-package" value="${outdir}/BarcodeReader.apk"/>
|
|
||||||
|
|
||||||
<!-- Tools -->
|
|
||||||
<property name="aapt" value="${android-tools}/aapt"/>
|
|
||||||
<property name="adb" value="${android-tools}/adb"/>
|
|
||||||
<property name="aidl" value="${android-tools}/aidl"/>
|
|
||||||
<!-- dx is a special case as it is a .bat file on Windows -->
|
|
||||||
<condition property="dx" value="${android-tools}/dx.bat" else="${android-tools}/dx">
|
|
||||||
<os family="windows"/>
|
|
||||||
</condition>
|
|
||||||
|
|
||||||
<property name="zip" value="zip"/>
|
|
||||||
<property name="android-jar" value="${sdk-folder}/android.jar"/>
|
|
||||||
|
|
||||||
<!-- Rules -->
|
|
||||||
|
|
||||||
<target name="init">
|
|
||||||
<tstamp/>
|
|
||||||
<fail message="Please set 'android-m3-home' in build.properties">
|
|
||||||
<condition>
|
|
||||||
<not>
|
|
||||||
<available file="${android-m3-home}" type="dir"/>
|
|
||||||
</not>
|
|
||||||
</condition>
|
|
||||||
</fail>
|
|
||||||
<fail message="Please build 'core' first">
|
|
||||||
<condition>
|
|
||||||
<not>
|
|
||||||
<available file="../core/core.jar" type="file"/>
|
|
||||||
</not>
|
|
||||||
</condition>
|
|
||||||
</fail>
|
|
||||||
<fail message="Please put proguard.jar in 'bin' under the WTK install directory">
|
|
||||||
<condition>
|
|
||||||
<and>
|
|
||||||
<not>
|
|
||||||
<isset property="debug"/>
|
|
||||||
</not>
|
|
||||||
<not>
|
|
||||||
<available file="${WTK-home}/bin/proguard.jar" type="file"/>
|
|
||||||
</not>
|
|
||||||
</and>
|
|
||||||
</condition>
|
|
||||||
</fail>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<!-- Create the output directories if they don't exist yet. -->
|
|
||||||
<target name="dirs">
|
|
||||||
<mkdir dir="${outdir}"/>
|
|
||||||
<mkdir dir="${outdir-classes}"/>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<!-- Generate the R.java file for this project's resources. -->
|
|
||||||
<target name="resource-src" depends="dirs">
|
|
||||||
|
|
||||||
<copy file="strings.xml.template" tofile="res/values/strings.xml" overwrite="true">
|
|
||||||
<filterset>
|
|
||||||
<filter token="VERSION" value="${version}"/>
|
|
||||||
</filterset>
|
|
||||||
</copy>
|
|
||||||
|
|
||||||
<echo>Generating R.java...</echo>
|
|
||||||
<exec executable="${aapt}" failonerror="true">
|
|
||||||
<arg value="compile"/>
|
|
||||||
<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">
|
|
||||||
<apply executable="${aidl}" failonerror="true">
|
|
||||||
<fileset dir="${srcdir}">
|
|
||||||
<include name="**/*.aidl"/>
|
|
||||||
</fileset>
|
|
||||||
</apply>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<!-- Compile this project's .java files into .class files. -->
|
|
||||||
<target name="compile" depends="init, clean, dirs, resource-src, aidl">
|
|
||||||
<javac encoding="ascii" target="1.5" debug="true" optimize="true" extdirs=""
|
|
||||||
srcdir="."
|
|
||||||
destdir="${outdir-classes}"
|
|
||||||
bootclasspath="${android-jar}">
|
|
||||||
<classpath>
|
|
||||||
<pathelement location="../core/core.jar"/>
|
|
||||||
</classpath>
|
|
||||||
</javac>
|
|
||||||
<unzip src="../core/core.jar" dest="${outdir-classes}"/>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="optimize" depends="compile" unless="debug">
|
|
||||||
<jar basedir="${outdir-classes}" destfile="temp.jar"/>
|
|
||||||
<java jar="${WTK-home}/bin/proguard.jar" fork="true" failonerror="true">
|
|
||||||
<jvmarg value="-Dmaximum.inlined.code.length=32"/>
|
|
||||||
<arg value="-injars temp.jar"/>
|
|
||||||
<arg value="-outjars optimized.jar"/>
|
|
||||||
<arg value="-libraryjars ${android-jar}"/>
|
|
||||||
<arg value="-dontpreverify"/>
|
|
||||||
<arg value="-dontobfuscate"/>
|
|
||||||
<!-- Temporary workaround to keep important stuff in the client, while inlining core. -->
|
|
||||||
<arg value="-keep class com.google.zxing.client.android.BarcodeReaderCaptureActivity { *; }"/>
|
|
||||||
<arg value="-keep class com.google.zxing.client.android.CameraManager { *; }"/>
|
|
||||||
<arg value="-keep class com.google.zxing.client.android.CameraThread { *; }"/>
|
|
||||||
<arg value="-optimizationpasses 7"/>
|
|
||||||
<arg value="-overloadaggressively"/>
|
|
||||||
<arg value="-verbose"/>
|
|
||||||
<!-- Needed to allow getters which refer to private members to be inlined. -->
|
|
||||||
<arg value="-allowaccessmodification"/>
|
|
||||||
</java>
|
|
||||||
<delete file="temp.jar"/>
|
|
||||||
<delete dir="${outdir-classes}"/>
|
|
||||||
<mkdir dir="${outdir-classes}"/>
|
|
||||||
<unzip src="optimized.jar" dest="${outdir-classes}"/>
|
|
||||||
<delete file="optimized.jar"/>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<!-- Convert this project's .class files into .dex files. -->
|
|
||||||
<target name="dex" depends="compile, optimize">
|
|
||||||
|
|
||||||
<condition property="locals" value="full" else="none">
|
|
||||||
<isset property="debug"/>
|
|
||||||
</condition>
|
|
||||||
<condition property="positions" value="lines" else="none">
|
|
||||||
<isset property="debug"/>
|
|
||||||
</condition>
|
|
||||||
|
|
||||||
<exec executable="${dx}" failonerror="true">
|
|
||||||
<arg value="--dex"/>
|
|
||||||
<arg value="--optimize"/>
|
|
||||||
<arg value="--output=${intermediate-dex}"/>
|
|
||||||
<arg value="--locals=${locals}"/>
|
|
||||||
<arg value="--positions=${positions}"/>
|
|
||||||
<arg path="${outdir-classes}"/>
|
|
||||||
</exec>
|
|
||||||
</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="-c"/>
|
|
||||||
<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="${out-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="-c"/>
|
|
||||||
<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="${out-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>
|
|
||||||
|
|
||||||
<!-- Put the project's .class files into the output package file. -->
|
|
||||||
<target name="package-java" depends="compile, package-res">
|
|
||||||
<echo>Packaging java...</echo>
|
|
||||||
<jar destfile="${out-package}"
|
|
||||||
basedir="${outdir-classes}"
|
|
||||||
update="true"/>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<!-- Put the project's .dex files into the output package file. -->
|
|
||||||
<target name="package-dex" depends="dex, package-res">
|
|
||||||
<echo>Packaging dex...</echo>
|
|
||||||
<exec executable="${zip}" failonerror="true">
|
|
||||||
<arg value="-qj"/>
|
|
||||||
<arg value="${out-package}"/>
|
|
||||||
<arg value="${intermediate-dex}"/>
|
|
||||||
</exec>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<!-- 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>
|
|
||||||
|
|
||||||
</project>
|
|
Binary file not shown.
Before Width: | Height: | Size: 5.8 KiB |
|
@ -1,65 +0,0 @@
|
||||||
<?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.
|
|
||||||
-->
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
|
|
||||||
<FrameLayout id="@+id/preview_view"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:background="#00000000">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="#00000000"/>
|
|
||||||
|
|
||||||
<!-- FIXME(dswitkin): Temporary hack to force the height to 48 pixels-->
|
|
||||||
<LinearLayout id="@+id/status_view"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="48px"
|
|
||||||
android:layout_weight="0"
|
|
||||||
android:background="#50000000"
|
|
||||||
android:baselineAligned="false"
|
|
||||||
android:padding="4px">
|
|
||||||
|
|
||||||
<TextView id="@+id/status_text_view"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="left|center_vertical"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/msg_default_status"
|
|
||||||
android:textColor="#ffffff"/>
|
|
||||||
|
|
||||||
<Button id="@+id/status_action_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center|fill_horizontal"
|
|
||||||
android:visibility="gone"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
Binary file not shown.
|
@ -1,39 +0,0 @@
|
||||||
<?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.
|
|
||||||
-->
|
|
||||||
<resources>
|
|
||||||
<!-- Messages IDs -->
|
|
||||||
<item type="id" name="preview"/>
|
|
||||||
<item type="id" name="decode"/>
|
|
||||||
<item type="id" name="save"/>
|
|
||||||
<item type="id" name="restart_preview"/>
|
|
||||||
<item type="id" name="quit"/>
|
|
||||||
<item type="id" name="set_decode_all_mode"/>
|
|
||||||
<item type="id" name="set_decode_1D_mode"/>
|
|
||||||
<item type="id" name="set_decode_QR_mode"/>
|
|
||||||
<item type="id" name="toggle_tracing"/>
|
|
||||||
<item type="id" name="decode_started"/>
|
|
||||||
<item type="id" name="decode_succeeded"/>
|
|
||||||
<item type="id" name="decode_failed"/>
|
|
||||||
<item type="id" name="save_succeeded"/>
|
|
||||||
<item type="id" name="save_failed"/>
|
|
||||||
|
|
||||||
<!-- Objects in the view hierarchy -->
|
|
||||||
<item type="id" name="preview_view"/>
|
|
||||||
<item type="id" name="status_action_button"/>
|
|
||||||
<item type="id" name="status_text_view"/>
|
|
||||||
<item type="id" name="status_view"/>
|
|
||||||
</resources>
|
|
|
@ -1,82 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2007 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
|
||||||
|
|
||||||
import android.graphics.Matrix;
|
|
||||||
import com.google.zxing.MonochromeBitmapSource;
|
|
||||||
import com.google.zxing.ReaderException;
|
|
||||||
import com.google.zxing.common.BitMatrix;
|
|
||||||
import com.google.zxing.common.GridSampler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation based on Android's
|
|
||||||
* {@link Matrix#setPolyToPoly(float[], int, float[], int, int)}
|
|
||||||
* class, which should offer faster performance for these matrix
|
|
||||||
* operations.
|
|
||||||
*
|
|
||||||
* @author srowen@google.com (Sean Owen)
|
|
||||||
*/
|
|
||||||
public final class AndroidGraphicsGridSampler extends GridSampler {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BitMatrix sampleGrid(MonochromeBitmapSource image,
|
|
||||||
int dimension,
|
|
||||||
float p1ToX, float p1ToY,
|
|
||||||
float p2ToX, float p2ToY,
|
|
||||||
float p3ToX, float p3ToY,
|
|
||||||
float p4ToX, float p4ToY,
|
|
||||||
float p1FromX, float p1FromY,
|
|
||||||
float p2FromX, float p2FromY,
|
|
||||||
float p3FromX, float p3FromY,
|
|
||||||
float p4FromX, float p4FromY) throws ReaderException {
|
|
||||||
|
|
||||||
Matrix transformMatrix = new Matrix();
|
|
||||||
boolean succeeded = transformMatrix.setPolyToPoly(
|
|
||||||
new float[] { p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY },
|
|
||||||
0,
|
|
||||||
new float[] { p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY },
|
|
||||||
0,
|
|
||||||
4
|
|
||||||
);
|
|
||||||
if (!succeeded) {
|
|
||||||
throw new ReaderException("Could not establish transformation matrix");
|
|
||||||
}
|
|
||||||
|
|
||||||
BitMatrix bits = new BitMatrix(dimension);
|
|
||||||
float[] points = new float[dimension << 1];
|
|
||||||
for (int i = 0; i < dimension; i++) {
|
|
||||||
int max = points.length;
|
|
||||||
float iValue = (float) i + 0.5f;
|
|
||||||
for (int j = 0; j < max; j += 2) {
|
|
||||||
points[j] = (float) (j >> 1) + 0.5f;
|
|
||||||
points[j + 1] = iValue;
|
|
||||||
}
|
|
||||||
transformMatrix.mapPoints(points);
|
|
||||||
// Quick check to see if points transformed to something inside the image;
|
|
||||||
// sufficent to check the endpoints
|
|
||||||
checkAndNudgePoints(image, points);
|
|
||||||
for (int j = 0; j < max; j += 2) {
|
|
||||||
if (image.isBlack((int) points[j], (int) points[j + 1])) {
|
|
||||||
// Black(-ish) pixel
|
|
||||||
bits.set(i, j >> 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import com.google.zxing.client.result.ParsedReaderResult;
|
|
||||||
import com.google.zxing.client.result.ParsedReaderResultType;
|
|
||||||
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link ParsedReaderResult} derived from a URI that encodes an Android
|
|
||||||
* {@link Intent}, and which should presumably trigger that intent on Android.
|
|
||||||
*
|
|
||||||
* @author srowen@google.com (Sean Owen)
|
|
||||||
*/
|
|
||||||
public final class AndroidIntentParsedResult extends ParsedReaderResult {
|
|
||||||
|
|
||||||
private final Intent intent;
|
|
||||||
|
|
||||||
private AndroidIntentParsedResult(Intent intent) {
|
|
||||||
super(ParsedReaderResultType.ANDROID_INTENT);
|
|
||||||
this.intent = intent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AndroidIntentParsedResult parse(String rawText) {
|
|
||||||
try {
|
|
||||||
return new AndroidIntentParsedResult(Intent.getIntent(rawText));
|
|
||||||
} catch (URISyntaxException urise) {
|
|
||||||
return null;
|
|
||||||
} catch (IllegalArgumentException iae) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Intent getIntent() {
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDisplayResult() {
|
|
||||||
return intent.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,286 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.PixelFormat;
|
|
||||||
import android.media.MediaPlayer;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.view.WindowManager.LayoutParams;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import com.google.zxing.Result;
|
|
||||||
import com.google.zxing.ResultPoint;
|
|
||||||
import com.google.zxing.client.result.ParsedReaderResult;
|
|
||||||
import com.google.zxing.client.result.ParsedReaderResultType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The barcode reader activity itself. This is loosely based on the CameraPreview
|
|
||||||
* example included in the Android SDK.
|
|
||||||
*
|
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
|
||||||
* @author Android Team (for CameraPreview example)
|
|
||||||
*/
|
|
||||||
public final class BarcodeReaderCaptureActivity extends Activity {
|
|
||||||
|
|
||||||
private CameraManager cameraManager;
|
|
||||||
private CameraSurfaceView surfaceView;
|
|
||||||
private CameraThread cameraThread;
|
|
||||||
private String lastResult;
|
|
||||||
|
|
||||||
private static final int ABOUT_ID = Menu.FIRST;
|
|
||||||
private static final int HELP_ID = Menu.FIRST + 1;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle icicle) {
|
|
||||||
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);
|
|
||||||
|
|
||||||
setContentView(R.layout.main);
|
|
||||||
|
|
||||||
cameraManager = new CameraManager(getApplication());
|
|
||||||
surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
|
|
||||||
surfaceView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
|
|
||||||
LayoutParams.FILL_PARENT));
|
|
||||||
|
|
||||||
ViewGroup previewView = (ViewGroup) findViewById(R.id.preview_view);
|
|
||||||
previewView.addView(surfaceView);
|
|
||||||
cameraThread = null;
|
|
||||||
|
|
||||||
// TODO re-enable this when issues with Matrix.setPolyToPoly() are resolved
|
|
||||||
//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();
|
|
||||||
resetStatusView();
|
|
||||||
cameraManager.openDriver();
|
|
||||||
if (cameraThread == null) {
|
|
||||||
cameraThread = new CameraThread(this, surfaceView, cameraManager, messageHandler);
|
|
||||||
cameraThread.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
if (cameraThread != null) {
|
|
||||||
cameraThread.quitSynchronously();
|
|
||||||
cameraThread = null;
|
|
||||||
}
|
|
||||||
cameraManager.closeDriver();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
||||||
switch (keyCode) {
|
|
||||||
case KeyEvent.KEYCODE_A:
|
|
||||||
cameraThread.setDecodeAllMode();
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_C:
|
|
||||||
Message save = Message.obtain(cameraThread.handler, R.id.save);
|
|
||||||
save.sendToTarget();
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_P:
|
|
||||||
cameraManager.setUsePreviewForDecode(true);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_Q:
|
|
||||||
cameraThread.setDecodeQRMode();
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_S:
|
|
||||||
cameraManager.setUsePreviewForDecode(false);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_T:
|
|
||||||
cameraThread.toggleTracing();
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_U:
|
|
||||||
cameraThread.setDecode1DMode();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return super.onKeyDown(keyCode, event);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
super.onCreateOptionsMenu(menu);
|
|
||||||
menu.add(0, ABOUT_ID, R.string.menu_about);
|
|
||||||
menu.add(0, HELP_ID, R.string.menu_help);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(Menu.Item item) {
|
|
||||||
Context context = getApplication();
|
|
||||||
switch (item.getId()) {
|
|
||||||
case ABOUT_ID:
|
|
||||||
showAlert(context.getString(R.string.title_about),
|
|
||||||
context.getString(R.string.msg_about),
|
|
||||||
context.getString(R.string.button_ok), null, true, null);
|
|
||||||
break;
|
|
||||||
case HELP_ID:
|
|
||||||
showAlert(context.getString(R.string.title_help),
|
|
||||||
context.getString(R.string.msg_help),
|
|
||||||
context.getString(R.string.button_ok), null, true, null);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Handler messageHandler = new Handler() {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
switch (message.what) {
|
|
||||||
case R.id.decode_succeeded:
|
|
||||||
int duration = message.arg1;
|
|
||||||
handleDecode((Result) message.obj, duration);
|
|
||||||
break;
|
|
||||||
case R.id.restart_preview:
|
|
||||||
restartPreview();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void restartPreview() {
|
|
||||||
resetStatusViewColor();
|
|
||||||
Message restart = Message.obtain(cameraThread.handler, R.id.restart_preview);
|
|
||||||
restart.sendToTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleDecode(Result rawResult, int duration) {
|
|
||||||
if (!rawResult.toString().equals(lastResult)) {
|
|
||||||
lastResult = rawResult.toString();
|
|
||||||
playBeepSound();
|
|
||||||
|
|
||||||
ResultPoint[] points = rawResult.getResultPoints();
|
|
||||||
if (points != null && points.length > 0) {
|
|
||||||
surfaceView.drawResultPoints(points);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextView textView = (TextView) findViewById(R.id.status_text_view);
|
|
||||||
ParsedReaderResult readerResult = parseReaderResult(rawResult);
|
|
||||||
textView.setText(readerResult.getDisplayResult() + " (" + duration + " ms)");
|
|
||||||
|
|
||||||
TextView actionButton = (TextView) findViewById(R.id.status_action_button);
|
|
||||||
int buttonText = getActionButtonText(readerResult.getType());
|
|
||||||
if (buttonText != 0) {
|
|
||||||
actionButton.setVisibility(View.VISIBLE);
|
|
||||||
actionButton.setText(buttonText);
|
|
||||||
View.OnClickListener handler = new ResultHandler(this, readerResult);
|
|
||||||
actionButton.setOnClickListener(handler);
|
|
||||||
actionButton.requestFocus();
|
|
||||||
} else {
|
|
||||||
actionButton.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
View statusView = findViewById(R.id.status_view);
|
|
||||||
statusView.setBackgroundColor(0xc000ff00);
|
|
||||||
|
|
||||||
// Show the green finder patterns for one second, then restart the preview
|
|
||||||
Message message = Message.obtain(messageHandler, R.id.restart_preview);
|
|
||||||
messageHandler.sendMessageDelayed(message, 1000);
|
|
||||||
} else {
|
|
||||||
restartPreview();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void playBeepSound() {
|
|
||||||
MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.beep);
|
|
||||||
mediaPlayer.prepare();
|
|
||||||
mediaPlayer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resetStatusView() {
|
|
||||||
resetStatusViewColor();
|
|
||||||
TextView textView = (TextView) findViewById(R.id.status_text_view);
|
|
||||||
textView.setText(R.string.msg_default_status);
|
|
||||||
View actionButton = findViewById(R.id.status_action_button);
|
|
||||||
actionButton.setVisibility(View.GONE);
|
|
||||||
lastResult = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resetStatusViewColor() {
|
|
||||||
View statusView = findViewById(R.id.status_view);
|
|
||||||
statusView.setBackgroundColor(0x50000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ParsedReaderResult parseReaderResult(Result rawResult) {
|
|
||||||
ParsedReaderResult readerResult = ParsedReaderResult.parseReaderResult(rawResult);
|
|
||||||
if (readerResult.getType().equals(ParsedReaderResultType.TEXT)) {
|
|
||||||
String rawText = rawResult.getText();
|
|
||||||
AndroidIntentParsedResult androidResult = AndroidIntentParsedResult.parse(rawText);
|
|
||||||
if (androidResult != null) {
|
|
||||||
Intent intent = androidResult.getIntent();
|
|
||||||
if (!Intent.VIEW_ACTION.equals(intent.getAction())) {
|
|
||||||
// For now, don't take anything that just parses as a View action. A lot
|
|
||||||
// of things are accepted as a View action by default.
|
|
||||||
readerResult = androidResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return readerResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getActionButtonText(ParsedReaderResultType type) {
|
|
||||||
int buttonText;
|
|
||||||
if (type.equals(ParsedReaderResultType.ADDRESSBOOK)) {
|
|
||||||
buttonText = R.string.button_add_contact;
|
|
||||||
} else if (type.equals(ParsedReaderResultType.URI) ||
|
|
||||||
type.equals(ParsedReaderResultType.BOOKMARK) ||
|
|
||||||
type.equals(ParsedReaderResultType.URLTO)) {
|
|
||||||
buttonText = R.string.button_open_browser;
|
|
||||||
} else if (type.equals(ParsedReaderResultType.EMAIL) ||
|
|
||||||
type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
|
|
||||||
buttonText = R.string.button_email;
|
|
||||||
} else if (type.equals(ParsedReaderResultType.UPC)) {
|
|
||||||
buttonText = R.string.button_lookup_product;
|
|
||||||
} else if (type.equals(ParsedReaderResultType.TEL)) {
|
|
||||||
buttonText = R.string.button_dial;
|
|
||||||
} else if (type.equals(ParsedReaderResultType.GEO)) {
|
|
||||||
buttonText = R.string.button_show_map;
|
|
||||||
} else {
|
|
||||||
buttonText = 0;
|
|
||||||
}
|
|
||||||
return buttonText;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,286 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Point;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.hardware.CameraDevice;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Display;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
import com.google.zxing.ResultPoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This object wraps the CameraDevice and expects to be the only one talking to it. The
|
|
||||||
* implementation encapsulates the steps needed to take preview-sized images and well as high
|
|
||||||
* resolution stills.
|
|
||||||
*
|
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
final class CameraManager {
|
|
||||||
|
|
||||||
private static final String TAG = "CameraManager";
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
private Point cameraResolution;
|
|
||||||
private Point stillResolution;
|
|
||||||
private Point previewResolution;
|
|
||||||
private int stillMultiplier;
|
|
||||||
private Point screenResolution;
|
|
||||||
private Rect framingRect;
|
|
||||||
private Bitmap bitmap;
|
|
||||||
private CameraDevice camera;
|
|
||||||
private final CameraDevice.CaptureParams params;
|
|
||||||
private boolean previewMode;
|
|
||||||
private boolean usePreviewForDecode;
|
|
||||||
|
|
||||||
CameraManager(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
getScreenResolution();
|
|
||||||
calculateStillResolution();
|
|
||||||
calculatePreviewResolution();
|
|
||||||
|
|
||||||
usePreviewForDecode = true;
|
|
||||||
setUsePreviewForDecode(false);
|
|
||||||
|
|
||||||
camera = null;
|
|
||||||
params = new CameraDevice.CaptureParams();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void openDriver() {
|
|
||||||
if (camera == null) {
|
|
||||||
camera = CameraDevice.open();
|
|
||||||
// If we're reopening the camera, we need to reset the capture params.
|
|
||||||
previewMode = false;
|
|
||||||
setPreviewMode(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void closeDriver() {
|
|
||||||
if (camera != null) {
|
|
||||||
camera.close();
|
|
||||||
camera = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void capturePreview(Canvas canvas) {
|
|
||||||
setPreviewMode(true);
|
|
||||||
camera.capture(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bitmap captureStill() {
|
|
||||||
setPreviewMode(usePreviewForDecode);
|
|
||||||
Canvas canvas = new Canvas(bitmap);
|
|
||||||
camera.capture(canvas);
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method exists to help us evaluate how to best set up and use the camera.
|
|
||||||
* @param usePreview Decode at preview resolution if true, else use still resolution.
|
|
||||||
*/
|
|
||||||
public void setUsePreviewForDecode(boolean usePreview) {
|
|
||||||
if (usePreviewForDecode != usePreview) {
|
|
||||||
usePreviewForDecode = usePreview;
|
|
||||||
if (usePreview) {
|
|
||||||
Log.v(TAG, "Creating bitmap at screen resolution: " + screenResolution.x + "," +
|
|
||||||
screenResolution.y);
|
|
||||||
bitmap = Bitmap.createBitmap(screenResolution.x, screenResolution.y, false);
|
|
||||||
} else {
|
|
||||||
Log.v(TAG, "Creating bitmap at still resolution: " + stillResolution.x + "," +
|
|
||||||
stillResolution.y);
|
|
||||||
bitmap = Bitmap.createBitmap(stillResolution.x, stillResolution.y, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 (framingRect == null) {
|
|
||||||
int size = stillResolution.x * screenResolution.x / previewResolution.x;
|
|
||||||
int leftOffset = (screenResolution.x - size) / 2;
|
|
||||||
int topOffset = (screenResolution.y - size) / 2;
|
|
||||||
framingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size);
|
|
||||||
Log.v(TAG, "Calculated framing rect: " + framingRect);
|
|
||||||
}
|
|
||||||
return framingRect;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the result points from still resolution coordinates to screen coordinates.
|
|
||||||
*
|
|
||||||
* @param points The points returned by the Reader subclass through Result.getResultPoints().
|
|
||||||
* @return An array of Points scaled to the size of the framing rect and offset appropriately
|
|
||||||
* so they can be drawn in screen coordinates.
|
|
||||||
*/
|
|
||||||
public Point[] convertResultPoints(ResultPoint[] points) {
|
|
||||||
Rect frame = getFramingRect();
|
|
||||||
int frameSize = frame.width();
|
|
||||||
int count = points.length;
|
|
||||||
Point[] output = new Point[count];
|
|
||||||
for (int x = 0; x < count; x++) {
|
|
||||||
output[x] = new Point();
|
|
||||||
if (usePreviewForDecode) {
|
|
||||||
output[x].x = (int) (points[x].getX() + 0.5f);
|
|
||||||
output[x].y = (int) (points[x].getY() + 0.5f);
|
|
||||||
} else {
|
|
||||||
output[x].x = frame.left + (int) (points[x].getX() * frameSize / stillResolution.x + 0.5f);
|
|
||||||
output[x].y = frame.top + (int) (points[x].getY() * frameSize / stillResolution.y + 0.5f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
private void setPreviewMode(boolean on) {
|
|
||||||
if (on != previewMode) {
|
|
||||||
if (on) {
|
|
||||||
params.type = 1; // preview
|
|
||||||
params.srcWidth = previewResolution.x;
|
|
||||||
params.srcHeight = previewResolution.y;
|
|
||||||
params.leftPixel = (cameraResolution.x - params.srcWidth) / 2;
|
|
||||||
params.topPixel = (cameraResolution.y - params.srcHeight) / 2;
|
|
||||||
params.outputWidth = screenResolution.x;
|
|
||||||
params.outputHeight = screenResolution.y;
|
|
||||||
params.dataFormat = 2; // RGB565
|
|
||||||
} else {
|
|
||||||
params.type = 0; // still
|
|
||||||
params.srcWidth = stillResolution.x * stillMultiplier;
|
|
||||||
params.srcHeight = stillResolution.y * stillMultiplier;
|
|
||||||
params.leftPixel = (cameraResolution.x - params.srcWidth) / 2;
|
|
||||||
params.topPixel = (cameraResolution.y - params.srcHeight) / 2;
|
|
||||||
params.outputWidth = stillResolution.x;
|
|
||||||
params.outputHeight = stillResolution.y;
|
|
||||||
params.dataFormat = 2; // RGB565
|
|
||||||
}
|
|
||||||
String captureType = on ? "preview" : "still";
|
|
||||||
Log.v(TAG, "Setting params for " + captureType + ": srcWidth " + params.srcWidth +
|
|
||||||
" srcHeight " + params.srcHeight + " leftPixel " + params.leftPixel + " topPixel " +
|
|
||||||
params.topPixel + " outputWidth " + params.outputWidth + " outputHeight " +
|
|
||||||
params.outputHeight);
|
|
||||||
camera.setCaptureParams(params);
|
|
||||||
previewMode = on;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method determines how to take the highest quality image (i.e. the one which has the best
|
|
||||||
* chance of being decoded) given the capabilities of the camera. It is a balancing act between
|
|
||||||
* having enough resolution to read UPCs and having few enough pixels to keep the QR Code
|
|
||||||
* processing fast. The result is the dimensions of the rectangle to capture from the center of
|
|
||||||
* the sensor, plus a stillMultiplier which indicates whether we'll ask the driver to downsample
|
|
||||||
* for us. This has the added benefit of keeping the memory footprint of the bitmap as small as
|
|
||||||
* possible.
|
|
||||||
*/
|
|
||||||
private void calculateStillResolution() {
|
|
||||||
cameraResolution = getMaximumCameraResolution();
|
|
||||||
int minDimension = (cameraResolution.x < cameraResolution.y) ? cameraResolution.x :
|
|
||||||
cameraResolution.y;
|
|
||||||
int diagonalResolution = (int) Math.sqrt(cameraResolution.x * cameraResolution.x +
|
|
||||||
cameraResolution.y * cameraResolution.y);
|
|
||||||
float diagonalFov = getFieldOfView();
|
|
||||||
|
|
||||||
// Determine the field of view in the smaller dimension, then calculate how large an object
|
|
||||||
// would be at the minimum focus distance.
|
|
||||||
float fov = diagonalFov * minDimension / diagonalResolution;
|
|
||||||
double objectSize = Math.tan(Math.toRadians(fov / 2.0)) * getMinimumFocusDistance() * 2;
|
|
||||||
|
|
||||||
// Let's assume the largest barcode we might photograph at this distance is 3 inches across. By
|
|
||||||
// cropping to this size, we can avoid processing surrounding pixels, which helps with speed and
|
|
||||||
// accuracy.
|
|
||||||
// TODO(dswitkin): Handle a device with a great macro mode where objectSize < 4 inches.
|
|
||||||
double crop = 3.0 / objectSize;
|
|
||||||
int nativeResolution = (int) (minDimension * crop);
|
|
||||||
|
|
||||||
// The camera driver can only capture images which are a multiple of eight, so it's necessary to
|
|
||||||
// round up.
|
|
||||||
nativeResolution = ((nativeResolution + 7) >> 3) << 3;
|
|
||||||
if (nativeResolution > minDimension) {
|
|
||||||
nativeResolution = minDimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There's no point in capturing too much detail, so ask the driver to downsample. I haven't
|
|
||||||
// tried a non-integer multiple, but it seems unlikely to work.
|
|
||||||
double dpi = nativeResolution / objectSize;
|
|
||||||
stillMultiplier = 1;
|
|
||||||
if (dpi > 200) {
|
|
||||||
stillMultiplier = (int) (dpi / 200 + 1);
|
|
||||||
}
|
|
||||||
stillResolution = new Point(nativeResolution, nativeResolution);
|
|
||||||
Log.v(TAG, "FOV " + fov + " objectSize " + objectSize + " crop " + crop + " dpi " + dpi +
|
|
||||||
" nativeResolution " + nativeResolution + " stillMultiplier " + stillMultiplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The goal of the preview resolution is to show a little context around the framing rectangle
|
|
||||||
* which is the actual captured area in still mode.
|
|
||||||
*/
|
|
||||||
private void calculatePreviewResolution() {
|
|
||||||
if (previewResolution == null) {
|
|
||||||
int previewHeight = (int) (stillResolution.x * stillMultiplier * 1.5f);
|
|
||||||
int previewWidth = previewHeight * screenResolution.x / screenResolution.y;
|
|
||||||
previewWidth = ((previewWidth + 7) >> 3) << 3;
|
|
||||||
if (previewWidth > cameraResolution.x) previewWidth = cameraResolution.x;
|
|
||||||
previewHeight = previewWidth * screenResolution.y / screenResolution.x;
|
|
||||||
previewResolution = new Point(previewWidth, previewHeight);
|
|
||||||
Log.v(TAG, "previewWidth " + previewWidth + " previewHeight " + previewHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(dswitkin): These three methods have temporary constants until the new Camera API can
|
|
||||||
// provide the real values for the current device.
|
|
||||||
// Temporary: the camera's maximum resolution in pixels.
|
|
||||||
private static Point getMaximumCameraResolution() {
|
|
||||||
return new Point(1280, 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary: the diagonal field of view in degrees.
|
|
||||||
private static float getFieldOfView() {
|
|
||||||
return 60.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary: the minimum focus distance in inches.
|
|
||||||
private static float getMinimumFocusDistance() {
|
|
||||||
return 12.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Point getScreenResolution() {
|
|
||||||
if (screenResolution == null) {
|
|
||||||
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
|
||||||
Display display = manager.getDefaultDisplay();
|
|
||||||
screenResolution = new Point(display.getWidth(), display.getHeight());
|
|
||||||
}
|
|
||||||
return screenResolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,155 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Point;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.view.SurfaceHolder;
|
|
||||||
import android.view.SurfaceView;
|
|
||||||
import com.google.zxing.ResultPoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
final class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
|
|
||||||
|
|
||||||
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
|
|
||||||
|
|
||||||
private final CameraManager cameraManager;
|
|
||||||
private final SurfaceHolder surfaceHolder;
|
|
||||||
private boolean hasSurface;
|
|
||||||
private int scannerAlpha;
|
|
||||||
|
|
||||||
CameraSurfaceView(Context context, CameraManager cameraManager) {
|
|
||||||
super(context);
|
|
||||||
this.cameraManager = cameraManager;
|
|
||||||
|
|
||||||
// Install a SurfaceHolder.Callback so we get notified when the underlying surface is created
|
|
||||||
// and destroyed.
|
|
||||||
surfaceHolder = getHolder();
|
|
||||||
surfaceHolder.setCallback(this);
|
|
||||||
hasSurface = false;
|
|
||||||
scannerAlpha = 0;
|
|
||||||
surfaceHolder.setSizeFromLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean 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) {
|
|
||||||
// FIXME(dswitkin): The docs say this surface will be destroyed when this method returns. In
|
|
||||||
// practice this has not been a problem so far. I need to investigate.
|
|
||||||
hasSurface = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
|
|
||||||
// Surface size or format has changed. This won't happen because of the setFixedSize() call.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is only called from the WorkerThread. It's job is to grab the next preview frame
|
|
||||||
* from the camera, draw the framing rectangle, and blit everything to the screen.
|
|
||||||
*/
|
|
||||||
public void capturePreviewAndDraw() {
|
|
||||||
if (hasSurface) {
|
|
||||||
Canvas canvas = surfaceHolder.lockCanvas();
|
|
||||||
cameraManager.capturePreview(canvas);
|
|
||||||
Rect frame = cameraManager.getFramingRect();
|
|
||||||
int width = canvas.getBitmapWidth();
|
|
||||||
int height = canvas.getBitmapHeight();
|
|
||||||
|
|
||||||
// Draw the exterior (i.e. outside the framing rect) as half darkened
|
|
||||||
Paint paint = new Paint();
|
|
||||||
paint.setColor(Color.BLACK);
|
|
||||||
paint.setAlpha(96);
|
|
||||||
Rect box = new Rect(0, 0, width, frame.top);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
box.set(0, frame.top, frame.left, frame.bottom + 1);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
box.set(frame.right + 1, frame.top, width, frame.bottom + 1);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
box.set(0, frame.bottom + 1, width, height);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
|
|
||||||
// Draw a two pixel solid black border inside the framing rect
|
|
||||||
paint.setAlpha(255);
|
|
||||||
box.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
box.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
box.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
box.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
|
|
||||||
// Draw a red "laser scanner" line through the middle
|
|
||||||
paint.setColor(Color.RED);
|
|
||||||
paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
|
|
||||||
int middle = frame.height() / 2 + frame.top;
|
|
||||||
box.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
|
|
||||||
canvas.drawRect(box, paint);
|
|
||||||
|
|
||||||
surfaceHolder.unlockCanvasAndPost(canvas);
|
|
||||||
|
|
||||||
// This cheap animation is tied to the rate at which we pull previews from the camera.
|
|
||||||
scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw a line for 1D barcodes (which return two points) or otherwise a set of points returned
|
|
||||||
* from the decoder to indicate what we found.
|
|
||||||
* TODO(dswitkin): It might be nice to clear the framing rect and zoom in on the actual still that
|
|
||||||
* was captured, then paint the green points on it. This would also clear the red scanner line
|
|
||||||
* which doesn't make sense after the capture.
|
|
||||||
*
|
|
||||||
* @param resultPoints An array of points from the decoder, whose coordinates are expressed
|
|
||||||
* relative to the still image from the camera.
|
|
||||||
*/
|
|
||||||
public void drawResultPoints(ResultPoint[] resultPoints) {
|
|
||||||
if (hasSurface) {
|
|
||||||
Canvas canvas = surfaceHolder.lockCanvas();
|
|
||||||
Paint paint = new Paint();
|
|
||||||
paint.setColor(Color.GREEN);
|
|
||||||
paint.setAlpha(128);
|
|
||||||
|
|
||||||
Point[] points = cameraManager.convertResultPoints(resultPoints);
|
|
||||||
if (points.length == 2) {
|
|
||||||
paint.setStrokeWidth(4);
|
|
||||||
canvas.drawLine(points[0].x, points[0].y, points[1].x, points[1].y, paint);
|
|
||||||
} else {
|
|
||||||
paint.setStrokeWidth(10);
|
|
||||||
for (int x = 0; x < points.length; x++) {
|
|
||||||
canvas.drawPoint(points[x].x, points[x].y, paint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
surfaceHolder.unlockCanvasAndPost(canvas);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,173 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
|
||||||
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.os.Message;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This thread continuously pulls preview frames from the camera and draws them to the screen. It
|
|
||||||
* also asks the DecodeThread to process as many images as it can keep up with, and coordinates with
|
|
||||||
* the main thread to display the results.
|
|
||||||
*
|
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
final class CameraThread extends Thread {
|
|
||||||
|
|
||||||
public Handler handler;
|
|
||||||
|
|
||||||
private final CameraSurfaceView surfaceView;
|
|
||||||
private final Handler activityHandler;
|
|
||||||
private final DecodeThread decodeThread;
|
|
||||||
private State state;
|
|
||||||
|
|
||||||
private enum State {
|
|
||||||
PREVIEW,
|
|
||||||
DECODE,
|
|
||||||
SAVE,
|
|
||||||
DONE
|
|
||||||
}
|
|
||||||
|
|
||||||
CameraThread(BarcodeReaderCaptureActivity activity, CameraSurfaceView surfaceView,
|
|
||||||
CameraManager cameraManager, Handler activityHandler) {
|
|
||||||
this.surfaceView = surfaceView;
|
|
||||||
this.activityHandler = activityHandler;
|
|
||||||
|
|
||||||
decodeThread = new DecodeThread(activity, cameraManager);
|
|
||||||
decodeThread.start();
|
|
||||||
state = State.DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Looper.prepare();
|
|
||||||
handler = new Handler() {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
switch (message.what) {
|
|
||||||
case R.id.preview:
|
|
||||||
if (state == State.PREVIEW) {
|
|
||||||
surfaceView.capturePreviewAndDraw();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case R.id.save:
|
|
||||||
state = State.SAVE;
|
|
||||||
Message save = Message.obtain(decodeThread.handler, R.id.save);
|
|
||||||
save.sendToTarget();
|
|
||||||
break;
|
|
||||||
case R.id.restart_preview:
|
|
||||||
restartPreviewAndDecode();
|
|
||||||
break;
|
|
||||||
case R.id.quit:
|
|
||||||
state = State.DONE;
|
|
||||||
Message quit = Message.obtain(decodeThread.handler, R.id.quit);
|
|
||||||
quit.sendToTarget();
|
|
||||||
try {
|
|
||||||
decodeThread.join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
Looper.myLooper().quit();
|
|
||||||
break;
|
|
||||||
case R.id.decode_started:
|
|
||||||
// Since the decoder is done with the camera, continue fetching preview frames.
|
|
||||||
state = State.PREVIEW;
|
|
||||||
break;
|
|
||||||
case R.id.decode_succeeded:
|
|
||||||
state = State.DONE;
|
|
||||||
// Message.copyFrom() did not work as expected, hence this workaround.
|
|
||||||
Message success = Message.obtain(activityHandler, R.id.decode_succeeded, message.obj);
|
|
||||||
success.arg1 = message.arg1;
|
|
||||||
success.sendToTarget();
|
|
||||||
break;
|
|
||||||
case R.id.decode_failed:
|
|
||||||
// We're decoding as fast as possible, so when one fails, start another.
|
|
||||||
startDecode();
|
|
||||||
break;
|
|
||||||
case R.id.save_succeeded:
|
|
||||||
// TODO: Put up a non-blocking status message
|
|
||||||
restartPreviewAndDecode();
|
|
||||||
break;
|
|
||||||
case R.id.save_failed:
|
|
||||||
// TODO: Put up a blocking error message
|
|
||||||
restartPreviewAndDecode();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == State.PREVIEW) {
|
|
||||||
Message preview = Message.obtain(handler, R.id.preview);
|
|
||||||
preview.sendToTarget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
decodeThread.setCameraThreadHandler(handler);
|
|
||||||
|
|
||||||
// Start ourselves capturing previews
|
|
||||||
restartPreviewAndDecode();
|
|
||||||
Looper.loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void quitSynchronously() {
|
|
||||||
Message quit = Message.obtain(handler, R.id.quit);
|
|
||||||
quit.sendToTarget();
|
|
||||||
try {
|
|
||||||
join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDecodeAllMode() {
|
|
||||||
Message message = Message.obtain(decodeThread.handler, R.id.set_decode_all_mode);
|
|
||||||
message.sendToTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDecode1DMode() {
|
|
||||||
Message message = Message.obtain(decodeThread.handler, R.id.set_decode_1D_mode);
|
|
||||||
message.sendToTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDecodeQRMode() {
|
|
||||||
Message message = Message.obtain(decodeThread.handler, R.id.set_decode_QR_mode);
|
|
||||||
message.sendToTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void toggleTracing() {
|
|
||||||
Message message = Message.obtain(decodeThread.handler, R.id.toggle_tracing);
|
|
||||||
message.sendToTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a decode if possible, but not now if the DecodeThread is in the middle of saving.
|
|
||||||
*/
|
|
||||||
private void startDecode() {
|
|
||||||
if (state != State.SAVE) {
|
|
||||||
state = State.DECODE;
|
|
||||||
Message decode = Message.obtain(decodeThread.handler, R.id.decode);
|
|
||||||
decode.sendToTarget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Take one preview to update the screen, then do a decode and continue previews.
|
|
||||||
*/
|
|
||||||
private void restartPreviewAndDecode() {
|
|
||||||
state = State.PREVIEW;
|
|
||||||
surfaceView.capturePreviewAndDraw();
|
|
||||||
startDecode();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,222 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.os.Debug;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
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.Date;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This thread does all the heavy lifting of decoding the images. It can also save images to flash
|
|
||||||
* for debugging purposes.
|
|
||||||
*
|
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
final class DecodeThread extends Thread {
|
|
||||||
|
|
||||||
public Handler handler;
|
|
||||||
|
|
||||||
private final BarcodeReaderCaptureActivity activity;
|
|
||||||
private final CameraManager cameraManager;
|
|
||||||
private Hashtable<DecodeHintType, Object> hints;
|
|
||||||
private Handler cameraThreadHandler;
|
|
||||||
private int methodTraceCount;
|
|
||||||
private boolean tracing;
|
|
||||||
|
|
||||||
DecodeThread(BarcodeReaderCaptureActivity activity, CameraManager cameraManager) {
|
|
||||||
this.activity = activity;
|
|
||||||
this.cameraManager = cameraManager;
|
|
||||||
methodTraceCount = 0;
|
|
||||||
tracing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Looper.prepare();
|
|
||||||
handler = new Handler() {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
switch (message.what) {
|
|
||||||
case R.id.decode:
|
|
||||||
captureAndDecode();
|
|
||||||
break;
|
|
||||||
case R.id.save:
|
|
||||||
captureAndSave();
|
|
||||||
break;
|
|
||||||
case R.id.quit:
|
|
||||||
Looper.myLooper().quit();
|
|
||||||
break;
|
|
||||||
case R.id.set_decode_all_mode:
|
|
||||||
setDecodeAllMode();
|
|
||||||
break;
|
|
||||||
case R.id.set_decode_1D_mode:
|
|
||||||
setDecode1DMode();
|
|
||||||
break;
|
|
||||||
case R.id.set_decode_QR_mode:
|
|
||||||
setDecodeQRMode();
|
|
||||||
break;
|
|
||||||
case R.id.toggle_tracing:
|
|
||||||
tracing = !tracing;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Looper.loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCameraThreadHandler(Handler cameraThreadHandler) {
|
|
||||||
this.cameraThreadHandler = cameraThreadHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setDecodeAllMode() {
|
|
||||||
hints = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
private void setDecode1DMode() {
|
|
||||||
hints = new Hashtable<DecodeHintType, Object>(3);
|
|
||||||
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setDecodeQRMode() {
|
|
||||||
hints = new Hashtable<DecodeHintType, Object>(3);
|
|
||||||
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>();
|
|
||||||
vector.addElement(BarcodeFormat.QR_CODE);
|
|
||||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void captureAndDecode() {
|
|
||||||
Date startDate = new Date();
|
|
||||||
Bitmap bitmap = cameraManager.captureStill();
|
|
||||||
// Let the CameraThread know it can resume previews while the decoding continues in parallel.
|
|
||||||
Message restart = Message.obtain(cameraThreadHandler, R.id.decode_started);
|
|
||||||
restart.sendToTarget();
|
|
||||||
|
|
||||||
if (tracing) {
|
|
||||||
Debug.startMethodTracing("/sdcard/ZXingDecodeThread" + methodTraceCount);
|
|
||||||
methodTraceCount++;
|
|
||||||
}
|
|
||||||
boolean success;
|
|
||||||
Result rawResult = null;
|
|
||||||
try {
|
|
||||||
MonochromeBitmapSource source = new RGBMonochromeBitmapSource(bitmap);
|
|
||||||
rawResult = new MultiFormatReader().decode(source, hints);
|
|
||||||
success = true;
|
|
||||||
} catch (ReaderException e) {
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
if (tracing) {
|
|
||||||
Debug.stopMethodTracing();
|
|
||||||
}
|
|
||||||
Date endDate = new Date();
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
Message message = Message.obtain(cameraThreadHandler, R.id.decode_succeeded, rawResult);
|
|
||||||
message.arg1 = (int) (endDate.getTime() - startDate.getTime());
|
|
||||||
message.sendToTarget();
|
|
||||||
} else {
|
|
||||||
Message message = Message.obtain(cameraThreadHandler, R.id.decode_failed);
|
|
||||||
message.sendToTarget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 captureAndSave() {
|
|
||||||
Bitmap bitmap = cameraManager.captureStill();
|
|
||||||
OutputStream outStream = getNewPhotoOutputStream();
|
|
||||||
if (outStream != null) {
|
|
||||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outStream);
|
|
||||||
try {
|
|
||||||
outStream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
Message success = Message.obtain(cameraThreadHandler, R.id.save_succeeded);
|
|
||||||
success.sendToTarget();
|
|
||||||
} else {
|
|
||||||
Message failure = Message.obtain(cameraThreadHandler, R.id.save_failed);
|
|
||||||
failure.sendToTarget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
try {
|
|
||||||
return new FileOutputStream(new File(barcodes, fileName));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Application application = activity.getApplication();
|
|
||||||
String fileName = getNewPhotoName();
|
|
||||||
try {
|
|
||||||
return application.openFileOutput(fileName, 0);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getNewPhotoName() {
|
|
||||||
Date now = new Date();
|
|
||||||
return "capture" + now.getTime() + ".jpg";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,167 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.google.zxing.BlackPointEstimationMethod;
|
|
||||||
import com.google.zxing.MonochromeBitmapSource;
|
|
||||||
import com.google.zxing.ReaderException;
|
|
||||||
import com.google.zxing.common.BitArray;
|
|
||||||
import com.google.zxing.common.BlackPointEstimator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This object implements MonochromeBitmapSource around an Android Bitmap.
|
|
||||||
*
|
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
|
||||||
* @author srowen@google.com (Sean Owen)
|
|
||||||
*/
|
|
||||||
final class RGBMonochromeBitmapSource implements MonochromeBitmapSource {
|
|
||||||
|
|
||||||
private final Bitmap image;
|
|
||||||
private int blackPoint;
|
|
||||||
private BlackPointEstimationMethod lastMethod;
|
|
||||||
private int lastArgument;
|
|
||||||
|
|
||||||
private static final int LUMINANCE_BITS = 5;
|
|
||||||
private static final int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
|
|
||||||
private static final int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
|
|
||||||
|
|
||||||
RGBMonochromeBitmapSource(Bitmap image) {
|
|
||||||
this.image = image;
|
|
||||||
blackPoint = 0x7F;
|
|
||||||
lastMethod = null;
|
|
||||||
lastArgument = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBlack(int x, int y) {
|
|
||||||
return computeRGBLuminance(image.getPixel(x, y)) < blackPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BitArray getBlackRow(int y, BitArray row, int startX, int getWidth) {
|
|
||||||
if (row == null || row.getSize() < getWidth) {
|
|
||||||
row = new BitArray(getWidth);
|
|
||||||
} else {
|
|
||||||
row.clear();
|
|
||||||
}
|
|
||||||
int[] pixelRow = new int[getWidth];
|
|
||||||
image.getPixels(pixelRow, 0, getWidth, startX, y, getWidth, 1);
|
|
||||||
|
|
||||||
// If the current decoder calculated the blackPoint based on one row, assume we're trying to
|
|
||||||
// decode a 1D barcode, and apply some sharpening.
|
|
||||||
// TODO: We may want to add a fifth parameter to request the amount of shapening to be done.
|
|
||||||
if (lastMethod == BlackPointEstimationMethod.ROW_SAMPLING) {
|
|
||||||
int left = computeRGBLuminance(pixelRow[0]);
|
|
||||||
int center = computeRGBLuminance(pixelRow[1]);
|
|
||||||
for (int i = 1; i < getWidth - 1; i++) {
|
|
||||||
int right = computeRGBLuminance(pixelRow[i + 1]);
|
|
||||||
// Simple -1 4 -1 box filter with a weight of 2
|
|
||||||
int luminance = ((center << 2) - left - right) >> 1;
|
|
||||||
if (luminance < blackPoint) {
|
|
||||||
row.set(i);
|
|
||||||
}
|
|
||||||
left = center;
|
|
||||||
center = right;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < getWidth; i++) {
|
|
||||||
if (computeRGBLuminance(pixelRow[i]) < blackPoint) {
|
|
||||||
row.set(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHeight() {
|
|
||||||
return image.height();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWidth() {
|
|
||||||
return image.width();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException {
|
|
||||||
if (!method.equals(lastMethod) || argument != lastArgument) {
|
|
||||||
int width = image.width();
|
|
||||||
int height = image.height();
|
|
||||||
int[] histogram = new int[LUMINANCE_BUCKETS];
|
|
||||||
if (method.equals(BlackPointEstimationMethod.TWO_D_SAMPLING)) {
|
|
||||||
int minDimension = width < height ? width : height;
|
|
||||||
int startI = height == minDimension ? 0 : (height - width) >> 1;
|
|
||||||
int startJ = width == minDimension ? 0 : (width - height) >> 1;
|
|
||||||
for (int n = 0; n < minDimension; n++) {
|
|
||||||
int pixel = image.getPixel(startJ + n, startI + n);
|
|
||||||
histogram[computeRGBLuminance(pixel) >> LUMINANCE_SHIFT]++;
|
|
||||||
}
|
|
||||||
} else if (method.equals(BlackPointEstimationMethod.ROW_SAMPLING)) {
|
|
||||||
if (argument < 0 || argument >= height) {
|
|
||||||
throw new IllegalArgumentException("Row is not within the image: " + argument);
|
|
||||||
}
|
|
||||||
int[] pixelRow = new int[width];
|
|
||||||
image.getPixels(pixelRow, 0, width, 0, argument, width, 1);
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
histogram[computeRGBLuminance(pixelRow[x]) >> LUMINANCE_SHIFT]++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Unknown method: " + method);
|
|
||||||
}
|
|
||||||
blackPoint = BlackPointEstimator.estimate(histogram) << LUMINANCE_SHIFT;
|
|
||||||
lastMethod = method;
|
|
||||||
lastArgument = argument;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlackPointEstimationMethod getLastEstimationMethod() {
|
|
||||||
return lastMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MonochromeBitmapSource rotateCounterClockwise() {
|
|
||||||
throw new IllegalStateException("Rotate not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRotateSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An optimized approximation of a more proper conversion from RGB to luminance which
|
|
||||||
* only uses shifts. See BufferedImageMonochromeBitmapSource for an original version.
|
|
||||||
*
|
|
||||||
* @param pixel An ARGB input pixel
|
|
||||||
* @return An eight bit luminance value
|
|
||||||
*/
|
|
||||||
private static int computeRGBLuminance(int pixel) {
|
|
||||||
// Instead of multiplying by 306, 601, 117, we multiply by 256, 512, 256, so that
|
|
||||||
// the multiplies can be implemented as shifts.
|
|
||||||
//
|
|
||||||
// Really, it's:
|
|
||||||
//
|
|
||||||
// return ((((pixel >> 16) & 0xFF) << 8) +
|
|
||||||
// (((pixel >> 8) & 0xFF) << 9) +
|
|
||||||
// (( pixel & 0xFF) << 8)) >> 10;
|
|
||||||
//
|
|
||||||
// That is, we're replacing the coefficients in the original with powers of two,
|
|
||||||
// which can be implemented as shifts, even though changing the coefficients slightly
|
|
||||||
// corrupts the conversion. Not significant for our purposes.
|
|
||||||
//
|
|
||||||
// But we can get even cleverer and eliminate a few shifts:
|
|
||||||
return (((pixel & 0x00FF0000) >> 16) +
|
|
||||||
((pixel & 0x0000FF00) >> 7) +
|
|
||||||
( pixel & 0x000000FF )) >> 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,170 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.ContentURI;
|
|
||||||
import android.provider.Contacts;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Button;
|
|
||||||
import com.google.zxing.client.result.AddressBookAUParsedResult;
|
|
||||||
import com.google.zxing.client.result.AddressBookDoCoMoParsedResult;
|
|
||||||
import com.google.zxing.client.result.BookmarkDoCoMoParsedResult;
|
|
||||||
import com.google.zxing.client.result.EmailAddressParsedResult;
|
|
||||||
import com.google.zxing.client.result.EmailDoCoMoParsedResult;
|
|
||||||
import com.google.zxing.client.result.GeoParsedResult;
|
|
||||||
import com.google.zxing.client.result.ParsedReaderResult;
|
|
||||||
import com.google.zxing.client.result.ParsedReaderResultType;
|
|
||||||
import com.google.zxing.client.result.SMSParsedResult;
|
|
||||||
import com.google.zxing.client.result.SMSTOParsedResult;
|
|
||||||
import com.google.zxing.client.result.TelParsedResult;
|
|
||||||
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 to open other activities like GMail, Maps, etc.
|
|
||||||
*
|
|
||||||
* @author srowen@google.com (Sean Owen)
|
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
final class ResultHandler implements Button.OnClickListener {
|
|
||||||
|
|
||||||
private final Intent intent;
|
|
||||||
private final BarcodeReaderCaptureActivity captureActivity;
|
|
||||||
|
|
||||||
ResultHandler(BarcodeReaderCaptureActivity captureActivity, ParsedReaderResult result) {
|
|
||||||
this.captureActivity = captureActivity;
|
|
||||||
this.intent = resultToIntent(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Intent resultToIntent(ParsedReaderResult result) {
|
|
||||||
Intent intent = null;
|
|
||||||
ParsedReaderResultType type = result.getType();
|
|
||||||
if (type.equals(ParsedReaderResultType.ADDRESSBOOK)) {
|
|
||||||
AddressBookDoCoMoParsedResult addressResult = (AddressBookDoCoMoParsedResult) result;
|
|
||||||
intent = new Intent(Contacts.Intents.Insert.ACTION, Contacts.People.CONTENT_URI);
|
|
||||||
putExtra(intent, Contacts.Intents.Insert.NAME, addressResult.getName());
|
|
||||||
putExtra(intent, Contacts.Intents.Insert.PHONE, addressResult.getPhoneNumbers());
|
|
||||||
putExtra(intent, Contacts.Intents.Insert.EMAIL, addressResult.getEmail());
|
|
||||||
putExtra(intent, Contacts.Intents.Insert.NOTES, addressResult.getNote());
|
|
||||||
putExtra(intent, Contacts.Intents.Insert.POSTAL, addressResult.getAddress());
|
|
||||||
} else if (type.equals(ParsedReaderResultType.ADDRESSBOOK_AU)) {
|
|
||||||
AddressBookAUParsedResult addressResult = (AddressBookAUParsedResult) result;
|
|
||||||
intent = new Intent(Contacts.Intents.Insert.ACTION, Contacts.People.CONTENT_URI);
|
|
||||||
putExtra(intent, Contacts.Intents.Insert.NAME, addressResult.getNames());
|
|
||||||
putExtra(intent, Contacts.Intents.Insert.PHONE, addressResult.getPhoneNumbers());
|
|
||||||
putExtra(intent, Contacts.Intents.Insert.EMAIL, addressResult.getEmails());
|
|
||||||
putExtra(intent, Contacts.Intents.Insert.NOTES, addressResult.getNote());
|
|
||||||
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) {
|
|
||||||
}
|
|
||||||
} else if (type.equals(ParsedReaderResultType.URLTO)) {
|
|
||||||
try {
|
|
||||||
intent = new Intent(Intent.VIEW_ACTION, new ContentURI(((URLTOParsedResult) result).getURI()));
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
}
|
|
||||||
} else if (type.equals(ParsedReaderResultType.EMAIL)) {
|
|
||||||
EmailDoCoMoParsedResult emailResult = (EmailDoCoMoParsedResult) result;
|
|
||||||
try {
|
|
||||||
intent = new Intent(Intent.SENDTO_ACTION, new ContentURI(emailResult.getMailtoURI()));
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
}
|
|
||||||
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.getMailtoURI()));
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
}
|
|
||||||
putExtra(intent, "subject", emailResult.getSubject());
|
|
||||||
putExtra(intent, "body", emailResult.getBody());
|
|
||||||
} else if (type.equals(ParsedReaderResultType.SMS)) {
|
|
||||||
SMSParsedResult smsResult = (SMSParsedResult) result;
|
|
||||||
try {
|
|
||||||
intent = new Intent(Intent.SENDTO_ACTION, new ContentURI(smsResult.getSMSURI()));
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
}
|
|
||||||
} else if (type.equals(ParsedReaderResultType.SMSTO)) {
|
|
||||||
SMSTOParsedResult smsToResult = (SMSTOParsedResult) result;
|
|
||||||
try {
|
|
||||||
intent = new Intent(Intent.SENDTO_ACTION, new ContentURI(smsToResult.getSMSURI()));
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
}
|
|
||||||
} else if (type.equals(ParsedReaderResultType.TEL)) {
|
|
||||||
TelParsedResult telResult = (TelParsedResult) result;
|
|
||||||
try {
|
|
||||||
intent = new Intent(Intent.DIAL_ACTION, new ContentURI(telResult.getTelURI()));
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
}
|
|
||||||
} else if (type.equals(ParsedReaderResultType.GEO)) {
|
|
||||||
GeoParsedResult geoResult = (GeoParsedResult) result;
|
|
||||||
try {
|
|
||||||
ContentURI geoURI = new ContentURI(geoResult.getGeoURI());
|
|
||||||
intent = new Intent(Intent.VIEW_ACTION, geoURI);
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
}
|
|
||||||
} 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) {
|
|
||||||
}
|
|
||||||
} else if (type.equals(ParsedReaderResultType.URI)) {
|
|
||||||
URIParsedResult uriResult = (URIParsedResult) result;
|
|
||||||
try {
|
|
||||||
intent = new Intent(Intent.VIEW_ACTION, new ContentURI(uriResult.getURI()));
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
}
|
|
||||||
} else if (type.equals(ParsedReaderResultType.ANDROID_INTENT)) {
|
|
||||||
intent = ((AndroidIntentParsedResult) result).getIntent();
|
|
||||||
}
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onClick(View view) {
|
|
||||||
if (intent != null) {
|
|
||||||
captureActivity.startActivity(intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Intent getIntent() {
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void putExtra(Intent intent, String key, String value) {
|
|
||||||
if (value != null && value.length() > 0) {
|
|
||||||
intent.putExtra(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void putExtra(Intent intent, String key, String[] value) {
|
|
||||||
if (value != null && value.length > 0) {
|
|
||||||
putExtra(intent, key, value[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
<?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.
|
|
||||||
-->
|
|
||||||
<resources>
|
|
||||||
<string name="app_name">Barcode Reader</string>
|
|
||||||
<string name="button_add_contact">Add Contact</string>
|
|
||||||
<string name="button_dial">Dial</string>
|
|
||||||
<string name="button_email">Email</string>
|
|
||||||
<string name="button_lookup_product">Lookup Product</string>
|
|
||||||
<string name="button_ok">OK</string>
|
|
||||||
<string name="button_open_browser">Open Browser</string>
|
|
||||||
<string name="button_show_map">Show Map</string>
|
|
||||||
<string name="menu_about">About...</string>
|
|
||||||
<string name="menu_help">Help...</string>
|
|
||||||
<string name="msg_about">ZXing Barcode Reader v@VERSION@\nhttp://code.google.com/p/zxing</string>
|
|
||||||
<string name="msg_help">A: Decode all barcodes\nC: Capture and save a JPEG\nP: Use the preview image for decoding\nQ: Decode only QR Codes\nS: Use a still image for decoding\nT: Toggle debug method tracing\nU: Decode only UPC/1D barcodes</string>
|
|
||||||
<string name="msg_default_status">Place a barcode inside the viewfinder rectangle to read it.</string>
|
|
||||||
<string name="title_about">About</string>
|
|
||||||
<string name="title_help">Keyboard Shortcut Help</string>
|
|
||||||
</resources>
|
|
Loading…
Reference in a new issue