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:
srowen 2008-06-11 12:51:38 +00:00
parent f431cae59f
commit 16f01d19bf
16 changed files with 0 additions and 2025 deletions

View file

@ -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>

View file

@ -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

View file

@ -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.

View file

@ -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>

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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();
}
}

View file

@ -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";
}
}

View file

@ -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;
}
}

View file

@ -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]);
}
}
}

View file

@ -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>