mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Update ZXingTest to work on 3.x+, mostly by removing the camera capture bit for now. It can come back after android/ is updated and can be cloned again. Updated android-integration with better API and ability to specify package. Now ZXingTest uses our integration code. It's updated for Android 2.x and reports camera params in a slightly better form. Also fixed a few Android 2.x issues and related intent integration stuff left over from other recent changes.
git-svn-id: https://zxing.googlecode.com/svn/trunk@2020 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
22e0f8daa2
commit
f328cb618e
|
@ -35,12 +35,16 @@
|
||||||
deprecation="true"
|
deprecation="true"
|
||||||
includeantruntime="false">
|
includeantruntime="false">
|
||||||
<classpath>
|
<classpath>
|
||||||
<pathelement location="${android-home}/platforms/android-10/android.jar"/>
|
<pathelement location="${android-home}/platforms/android-7/android.jar"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
</javac>
|
</javac>
|
||||||
<jar jarfile="android-integration.jar" basedir="build"/>
|
<jar jarfile="android-integration.jar" basedir="build"/>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
<target name="export" depends="build">
|
||||||
|
<copy file="android-integration.jar" todir="../androidtest/libs"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
<target name="clean">
|
<target name="clean">
|
||||||
<delete dir="build"/>
|
<delete dir="build"/>
|
||||||
<delete file="android-integration.jar"/>
|
<delete file="android-integration.jar"/>
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
<groupId>com.google.android</groupId>
|
<groupId>com.google.android</groupId>
|
||||||
<artifactId>android</artifactId>
|
<artifactId>android</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
<version>1.6_r2</version>
|
<version>2.1.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -16,14 +16,18 @@
|
||||||
|
|
||||||
package com.google.zxing.integration.android;
|
package com.google.zxing.integration.android;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.util.Arrays;
|
||||||
import java.lang.reflect.Method;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
@ -34,11 +38,11 @@ import android.util.Log;
|
||||||
*
|
*
|
||||||
* <h2>Initiating a barcode scan</h2>
|
* <h2>Initiating a barcode scan</h2>
|
||||||
*
|
*
|
||||||
* <p>Integration is essentially as easy as calling {@link #initiateScan(Activity)} and waiting
|
* <p>To integrate, create an instance of {@code IntentIntegrator} and call {@link #initiateScan()} and wait
|
||||||
* for the result in your app.</p>
|
* for the result in your app.</p>
|
||||||
*
|
*
|
||||||
* <p>It does require that the Barcode Scanner application is installed. The
|
* <p>It does require that the Barcode Scanner (or work-alike) application is installed. The
|
||||||
* {@link #initiateScan(Activity)} method will prompt the user to download the application, if needed.</p>
|
* {@link #initiateScan()} method will prompt the user to download the application, if needed.</p>
|
||||||
*
|
*
|
||||||
* <p>There are a few steps to using this integration. First, your {@link Activity} must implement
|
* <p>There are a few steps to using this integration. First, your {@link Activity} must implement
|
||||||
* the method {@link Activity#onActivityResult(int, int, Intent)} and include a line of code like this:</p>
|
* the method {@link Activity#onActivityResult(int, int, Intent)} and include a line of code like this:</p>
|
||||||
|
@ -54,23 +58,31 @@ import android.util.Log;
|
||||||
* }
|
* }
|
||||||
* }</pre>
|
* }</pre>
|
||||||
*
|
*
|
||||||
* <p>This is where you will handle a scan result.
|
* <p>This is where you will handle a scan result.</p>
|
||||||
* Second, just call this in response to a user action somewhere to begin the scan process:</p>
|
|
||||||
*
|
*
|
||||||
* <pre>{@code IntentIntegrator.initiateScan(yourActivity);}</pre>
|
* <p>Second, just call this in response to a user action somewhere to begin the scan process:</p>
|
||||||
*
|
*
|
||||||
* <p>You can use {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} or
|
* <pre>{@code
|
||||||
* {@link #initiateScan(Activity, int, int, int, int)} to customize the download prompt with
|
* IntentIntegrator integrator = new IntentIntegrator(yourActivity);
|
||||||
* different text labels.</p>
|
* integrator.initiateScan();
|
||||||
|
* }</pre>
|
||||||
*
|
*
|
||||||
* <p>Note that {@link #initiateScan(Activity)} returns an {@link AlertDialog} which is non-null if the
|
* <p>Note that {@link #initiateScan()} returns an {@link AlertDialog} which is non-null if the
|
||||||
* user was prompted to download the application. This lets the calling app potentially manage the dialog.
|
* user was prompted to download the application. This lets the calling app potentially manage the dialog.
|
||||||
* In particular, ideally, the app dismisses the dialog if it's still active in its {@link Activity#onPause()}
|
* In particular, ideally, the app dismisses the dialog if it's still active in its {@link Activity#onPause()}
|
||||||
* method.</p>
|
* method.</p>
|
||||||
*
|
*
|
||||||
|
* <p>You can use {@link #setTitle(String)} to customize the title of this download prompt dialog (or, use
|
||||||
|
* {@link #setTitleByID(int)} to set the title by string resource ID.) Likewise, the prompt message, and
|
||||||
|
* yes/no button labels can be changed.</p>
|
||||||
|
*
|
||||||
|
* <p>By default, this will only allow applications that are known to respond to this intent correctly
|
||||||
|
* do so. The apps that are allowed to response can be set with {@link #setTargetApplications(Collection)}.
|
||||||
|
* For example, set to {@link #TARGET_BARCODE_SCANNER_ONLY} to only target the Barcode Scanner app itself.</p>
|
||||||
|
*
|
||||||
* <h2>Sharing text via barcode</h2>
|
* <h2>Sharing text via barcode</h2>
|
||||||
*
|
*
|
||||||
* <p>To share text, encoded as a QR Code on-screen, similarly, see {@link #shareText(Activity, CharSequence)}.</p>
|
* <p>To share text, encoded as a QR Code on-screen, similarly, see {@link #shareText(CharSequence)}.</p>
|
||||||
*
|
*
|
||||||
* <p>Some code, particularly download integration, was contributed from the Anobiit application.</p>
|
* <p>Some code, particularly download integration, was contributed from the Anobiit application.</p>
|
||||||
*
|
*
|
||||||
|
@ -91,130 +103,162 @@ public final class IntentIntegrator {
|
||||||
public static final String DEFAULT_YES = "Yes";
|
public static final String DEFAULT_YES = "Yes";
|
||||||
public static final String DEFAULT_NO = "No";
|
public static final String DEFAULT_NO = "No";
|
||||||
|
|
||||||
private static final String PACKAGE = "com.google.zxing.client.android";
|
private static final String BS_PACKAGE = "com.google.zxing.client.android";
|
||||||
|
|
||||||
// supported barcode formats
|
// supported barcode formats
|
||||||
public static final String PRODUCT_CODE_TYPES = "UPC_A,UPC_E,EAN_8,EAN_13";
|
public static final Collection<String> PRODUCT_CODE_TYPES = list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "RSS_14");
|
||||||
public static final String ONE_D_CODE_TYPES = PRODUCT_CODE_TYPES + ",CODE_39,CODE_93,CODE_128";
|
public static final Collection<String> ONE_D_CODE_TYPES =
|
||||||
public static final String QR_CODE_TYPES = "QR_CODE";
|
list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "CODE_39", "CODE_93", "CODE_128",
|
||||||
public static final String ALL_CODE_TYPES = null;
|
"ITF", "RSS_14", "RSS_EXPANDED");
|
||||||
|
public static final Collection<String> QR_CODE_TYPES = Collections.singleton("QR_CODE");
|
||||||
|
public static final Collection<String> DATA_MATRIX_TYPES = Collections.singleton("DATA_MATRIX");
|
||||||
|
|
||||||
public static final Method PACKAGE_SETTER;
|
public static final Collection<String> ALL_CODE_TYPES = null;
|
||||||
static {
|
|
||||||
Method temp;
|
public static final Collection<String> TARGET_BARCODE_SCANNER_ONLY = Collections.singleton(BS_PACKAGE);
|
||||||
try {
|
public static final Collection<String> TARGET_ALL_KNOWN = list(
|
||||||
temp = Intent.class.getMethod("setPackage", String.class);
|
BS_PACKAGE, // Barcode Scanner
|
||||||
} catch (NoSuchMethodException nsme) {
|
"com.srowen.bs.android", // Barcode Scanner+
|
||||||
temp = null;
|
"com.srowen.bs.android.simple" // Barcode Scanner+ Simple
|
||||||
}
|
// TODO add more -- what else supports this intent?
|
||||||
PACKAGE_SETTER = temp;
|
);
|
||||||
|
|
||||||
|
private final Activity activity;
|
||||||
|
private String title;
|
||||||
|
private String message;
|
||||||
|
private String buttonYes;
|
||||||
|
private String buttonNo;
|
||||||
|
private Collection<String> targetApplications;
|
||||||
|
|
||||||
|
public IntentIntegrator(Activity activity) {
|
||||||
|
this.activity = activity;
|
||||||
|
title = DEFAULT_TITLE;
|
||||||
|
message = DEFAULT_MESSAGE;
|
||||||
|
buttonYes = DEFAULT_YES;
|
||||||
|
buttonNo = DEFAULT_NO;
|
||||||
|
targetApplications = TARGET_ALL_KNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntentIntegrator() {
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitleByID(int titleID) {
|
||||||
|
title = activity.getString(titleID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageByID(int messageID) {
|
||||||
|
message = activity.getString(messageID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getButtonYes() {
|
||||||
|
return buttonYes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setButtonYes(String buttonYes) {
|
||||||
|
this.buttonYes = buttonYes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setButtonYesByID(int buttonYesID) {
|
||||||
|
buttonYes = activity.getString(buttonYesID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getButtonNo() {
|
||||||
|
return buttonNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setButtonNo(String buttonNo) {
|
||||||
|
this.buttonNo = buttonNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setButtonNoByID(int buttonNoID) {
|
||||||
|
buttonNo = activity.getString(buttonNoID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<String> getTargetApplications() {
|
||||||
|
return targetApplications;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTargetApplications(Collection<String> targetApplications) {
|
||||||
|
this.targetApplications = targetApplications;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSingleTargetApplication(String targetApplication) {
|
||||||
|
this.targetApplications = Collections.singleton(targetApplication);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} --
|
* Initiates a scan for all known barcode types.
|
||||||
* same, but uses default English labels.
|
|
||||||
*/
|
*/
|
||||||
public static AlertDialog initiateScan(Activity activity) {
|
public AlertDialog initiateScan() {
|
||||||
return initiateScan(activity, DEFAULT_TITLE, DEFAULT_MESSAGE, DEFAULT_YES, DEFAULT_NO);
|
return initiateScan(ALL_CODE_TYPES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} --
|
* Initiates a scan only for a certain set of barcode types, given as strings corresponding
|
||||||
* same, but takes string IDs which refer
|
* to their names in ZXing's {@code BarcodeFormat} class like "UPC_A". You can supply constants
|
||||||
* to the {@link Activity}'s resource bundle entries.
|
* like {@link #PRODUCT_CODE_TYPES} for example.
|
||||||
*/
|
*/
|
||||||
public static AlertDialog initiateScan(Activity activity,
|
public AlertDialog initiateScan(Collection<String> desiredBarcodeFormats) {
|
||||||
int stringTitle,
|
Intent intentScan = new Intent(BS_PACKAGE + ".SCAN");
|
||||||
int stringMessage,
|
|
||||||
int stringButtonYes,
|
|
||||||
int stringButtonNo) {
|
|
||||||
return initiateScan(activity,
|
|
||||||
activity.getString(stringTitle),
|
|
||||||
activity.getString(stringMessage),
|
|
||||||
activity.getString(stringButtonYes),
|
|
||||||
activity.getString(stringButtonNo));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} --
|
|
||||||
* same, but scans for all supported barcode types.
|
|
||||||
* @param stringTitle title of dialog prompting user to download Barcode Scanner
|
|
||||||
* @param stringMessage text of dialog prompting user to download Barcode Scanner
|
|
||||||
* @param stringButtonYes text of button user clicks when agreeing to download
|
|
||||||
* Barcode Scanner (e.g. "Yes")
|
|
||||||
* @param stringButtonNo text of button user clicks when declining to download
|
|
||||||
* Barcode Scanner (e.g. "No")
|
|
||||||
* @return an {@link AlertDialog} if the user was prompted to download the app,
|
|
||||||
* null otherwise
|
|
||||||
*/
|
|
||||||
public static AlertDialog initiateScan(Activity activity,
|
|
||||||
CharSequence stringTitle,
|
|
||||||
CharSequence stringMessage,
|
|
||||||
CharSequence stringButtonYes,
|
|
||||||
CharSequence stringButtonNo) {
|
|
||||||
|
|
||||||
return initiateScan(activity,
|
|
||||||
stringTitle,
|
|
||||||
stringMessage,
|
|
||||||
stringButtonYes,
|
|
||||||
stringButtonNo,
|
|
||||||
ALL_CODE_TYPES);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invokes scanning.
|
|
||||||
*
|
|
||||||
* @param stringTitle title of dialog prompting user to download Barcode Scanner
|
|
||||||
* @param stringMessage text of dialog prompting user to download Barcode Scanner
|
|
||||||
* @param stringButtonYes text of button user clicks when agreeing to download
|
|
||||||
* Barcode Scanner (e.g. "Yes")
|
|
||||||
* @param stringButtonNo text of button user clicks when declining to download
|
|
||||||
* Barcode Scanner (e.g. "No")
|
|
||||||
* @param stringDesiredBarcodeFormats a comma separated list of codes you would
|
|
||||||
* like to scan for.
|
|
||||||
* @return an {@link AlertDialog} if the user was prompted to download the app,
|
|
||||||
* null otherwise
|
|
||||||
* @throws InterruptedException if timeout expires before a scan completes
|
|
||||||
*/
|
|
||||||
public static AlertDialog initiateScan(Activity activity,
|
|
||||||
CharSequence stringTitle,
|
|
||||||
CharSequence stringMessage,
|
|
||||||
CharSequence stringButtonYes,
|
|
||||||
CharSequence stringButtonNo,
|
|
||||||
CharSequence stringDesiredBarcodeFormats) {
|
|
||||||
Intent intentScan = new Intent(PACKAGE + ".SCAN");
|
|
||||||
setPackage(intentScan);
|
|
||||||
intentScan.addCategory(Intent.CATEGORY_DEFAULT);
|
intentScan.addCategory(Intent.CATEGORY_DEFAULT);
|
||||||
|
|
||||||
// check which types of codes to scan for
|
// check which types of codes to scan for
|
||||||
if (stringDesiredBarcodeFormats != null) {
|
if (desiredBarcodeFormats != null) {
|
||||||
// set the desired barcode types
|
// set the desired barcode types
|
||||||
intentScan.putExtra("SCAN_FORMATS", stringDesiredBarcodeFormats);
|
StringBuilder joinedByComma = new StringBuilder();
|
||||||
|
for (String format : desiredBarcodeFormats) {
|
||||||
|
if (joinedByComma.length() > 0) {
|
||||||
|
joinedByComma.append(',');
|
||||||
|
}
|
||||||
|
joinedByComma.append(format);
|
||||||
|
}
|
||||||
|
intentScan.putExtra("SCAN_FORMATS", joinedByComma.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
String targetAppPackage = findTargetAppPackage(intentScan);
|
||||||
|
if (targetAppPackage == null) {
|
||||||
|
return showDownloadDialog();
|
||||||
|
}
|
||||||
|
intentScan.setPackage(targetAppPackage);
|
||||||
activity.startActivityForResult(intentScan, REQUEST_CODE);
|
activity.startActivityForResult(intentScan, REQUEST_CODE);
|
||||||
return null;
|
return null;
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
return showDownloadDialog(activity, stringTitle, stringMessage, stringButtonYes, stringButtonNo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AlertDialog showDownloadDialog(final Activity activity,
|
private String findTargetAppPackage(Intent intent) {
|
||||||
CharSequence stringTitle,
|
PackageManager pm = activity.getPackageManager();
|
||||||
CharSequence stringMessage,
|
List<ResolveInfo> availableApps = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||||
CharSequence stringButtonYes,
|
if (availableApps != null) {
|
||||||
CharSequence stringButtonNo) {
|
for (ResolveInfo availableApp : availableApps) {
|
||||||
|
String packageName = availableApp.activityInfo.packageName;
|
||||||
|
if (targetApplications.contains(packageName)) {
|
||||||
|
return packageName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlertDialog showDownloadDialog() {
|
||||||
AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
|
AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
|
||||||
downloadDialog.setTitle(stringTitle);
|
downloadDialog.setTitle(title);
|
||||||
downloadDialog.setMessage(stringMessage);
|
downloadDialog.setMessage(message);
|
||||||
downloadDialog.setPositiveButton(stringButtonYes, new DialogInterface.OnClickListener() {
|
downloadDialog.setPositiveButton(buttonYes, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
Uri uri = Uri.parse("market://search?q=pname:" + PACKAGE);
|
Uri uri = Uri.parse("market://details?id=" + BS_PACKAGE);
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||||
try {
|
try {
|
||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
|
@ -224,7 +268,7 @@ public final class IntentIntegrator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
downloadDialog.setNegativeButton(stringButtonNo, new DialogInterface.OnClickListener() {
|
downloadDialog.setNegativeButton(buttonNo, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {}
|
public void onClick(DialogInterface dialogInterface, int i) {}
|
||||||
});
|
});
|
||||||
|
@ -246,79 +290,36 @@ public final class IntentIntegrator {
|
||||||
String contents = intent.getStringExtra("SCAN_RESULT");
|
String contents = intent.getStringExtra("SCAN_RESULT");
|
||||||
String formatName = intent.getStringExtra("SCAN_RESULT_FORMAT");
|
String formatName = intent.getStringExtra("SCAN_RESULT_FORMAT");
|
||||||
return new IntentResult(contents, formatName);
|
return new IntentResult(contents, formatName);
|
||||||
} else {
|
|
||||||
return new IntentResult(null, null);
|
|
||||||
}
|
}
|
||||||
|
return new IntentResult(null, null);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* See {@link #shareText(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} --
|
|
||||||
* same, but uses default English labels.
|
|
||||||
*/
|
|
||||||
public static void shareText(Activity activity, CharSequence text) {
|
|
||||||
shareText(activity, text, DEFAULT_TITLE, DEFAULT_MESSAGE, DEFAULT_YES, DEFAULT_NO);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See {@link #shareText(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} --
|
|
||||||
* same, but takes string IDs which refer to the {@link Activity}'s resource bundle entries.
|
|
||||||
*/
|
|
||||||
public static void shareText(Activity activity,
|
|
||||||
CharSequence text,
|
|
||||||
int stringTitle,
|
|
||||||
int stringMessage,
|
|
||||||
int stringButtonYes,
|
|
||||||
int stringButtonNo) {
|
|
||||||
shareText(activity,
|
|
||||||
text,
|
|
||||||
activity.getString(stringTitle),
|
|
||||||
activity.getString(stringMessage),
|
|
||||||
activity.getString(stringButtonYes),
|
|
||||||
activity.getString(stringButtonNo));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shares the given text by encoding it as a barcode, such that another user can
|
* Shares the given text by encoding it as a barcode, such that another user can
|
||||||
* scan the text off the screen of the device.
|
* scan the text off the screen of the device.
|
||||||
*
|
*
|
||||||
* @param text the text string to encode as a barcode
|
* @param text the text string to encode as a barcode
|
||||||
* @param stringTitle title of dialog prompting user to download Barcode Scanner
|
|
||||||
* @param stringMessage text of dialog prompting user to download Barcode Scanner
|
|
||||||
* @param stringButtonYes text of button user clicks when agreeing to download
|
|
||||||
* Barcode Scanner (e.g. "Yes")
|
|
||||||
* @param stringButtonNo text of button user clicks when declining to download
|
|
||||||
* Barcode Scanner (e.g. "No")
|
|
||||||
*/
|
*/
|
||||||
public static void shareText(Activity activity,
|
public void shareText(CharSequence text) {
|
||||||
CharSequence text,
|
|
||||||
CharSequence stringTitle,
|
|
||||||
CharSequence stringMessage,
|
|
||||||
CharSequence stringButtonYes,
|
|
||||||
CharSequence stringButtonNo) {
|
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.setAction(PACKAGE + ".ENCODE");
|
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||||
setPackage(intent);
|
intent.setAction(BS_PACKAGE + ".ENCODE");
|
||||||
intent.putExtra("ENCODE_TYPE", "TEXT_TYPE");
|
intent.putExtra("ENCODE_TYPE", "TEXT_TYPE");
|
||||||
intent.putExtra("ENCODE_DATA", text);
|
intent.putExtra("ENCODE_DATA", text);
|
||||||
try {
|
String targetAppPackage = findTargetAppPackage(intent);
|
||||||
|
if (targetAppPackage == null) {
|
||||||
|
showDownloadDialog();
|
||||||
|
} else {
|
||||||
|
intent.setPackage(targetAppPackage);
|
||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
showDownloadDialog(activity, stringTitle, stringMessage, stringButtonYes, stringButtonNo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setPackage(Intent intent) {
|
private static Collection<String> list(String... values) {
|
||||||
if (PACKAGE_SETTER != null) {
|
return Collections.unmodifiableCollection(Arrays.asList(values));
|
||||||
try {
|
|
||||||
PACKAGE_SETTER.invoke(intent, PACKAGE);
|
|
||||||
} catch (InvocationTargetException ite) {
|
|
||||||
Log.w(TAG, ite.getTargetException());
|
|
||||||
} catch (IllegalAccessException iae) {
|
|
||||||
Log.w(TAG, iae);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
# This file is used to override default values used by the Ant build system.
|
|
||||||
#
|
|
||||||
# This file must be checked in Version Control Systems, as it is
|
|
||||||
# integral to the build system of your project.
|
|
||||||
|
|
||||||
# The name of your application package as defined in the manifest.
|
|
||||||
# Used by the 'uninstall' rule.
|
|
||||||
application-package=com.google.zxing.client.android
|
|
||||||
|
|
||||||
# The name of the source folder.
|
|
||||||
#source-folder=src
|
|
||||||
|
|
||||||
# The name of the output folder.
|
|
||||||
#out-folder=bin
|
|
||||||
|
|
||||||
external-libs-folder=external-libs
|
|
|
@ -1,11 +0,0 @@
|
||||||
# This file is automatically generated by Android Tools.
|
|
||||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
|
||||||
#
|
|
||||||
# This file must be checked in Version Control Systems.
|
|
||||||
#
|
|
||||||
# To customize properties used by the Ant build system use,
|
|
||||||
# "build.properties", and override values to adapt the script to your
|
|
||||||
# project structure.
|
|
||||||
|
|
||||||
# Project target.
|
|
||||||
target=android-10
|
|
|
@ -99,11 +99,13 @@ final class QRCodeEncoder {
|
||||||
private boolean encodeContentsFromZXingIntent(Intent intent) {
|
private boolean encodeContentsFromZXingIntent(Intent intent) {
|
||||||
// Default to QR_CODE if no format given.
|
// Default to QR_CODE if no format given.
|
||||||
String formatString = intent.getStringExtra(Intents.Encode.FORMAT);
|
String formatString = intent.getStringExtra(Intents.Encode.FORMAT);
|
||||||
|
format = null;
|
||||||
|
if (formatString != null) {
|
||||||
try {
|
try {
|
||||||
format = BarcodeFormat.valueOf(formatString);
|
format = BarcodeFormat.valueOf(formatString);
|
||||||
} catch (IllegalArgumentException iae) {
|
} catch (IllegalArgumentException iae) {
|
||||||
// Ignore it then
|
// Ignore it then
|
||||||
format = null;
|
}
|
||||||
}
|
}
|
||||||
if (format == null || format == BarcodeFormat.QR_CODE) {
|
if (format == null || format == BarcodeFormat.QR_CODE) {
|
||||||
String type = intent.getStringExtra(Intents.Encode.TYPE);
|
String type = intent.getStringExtra(Intents.Encode.TYPE);
|
||||||
|
|
|
@ -16,12 +16,11 @@
|
||||||
-->
|
-->
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.google.zxing.client.androidtest"
|
package="com.google.zxing.client.androidtest"
|
||||||
android:versionName="1.13"
|
android:versionName="1.2"
|
||||||
android:versionCode="5">
|
android:versionCode="6"
|
||||||
<!-- We require Cupcake (Android 1.5) or later, but are really targeting Donut. -->
|
android:installLocation="auto">
|
||||||
<uses-sdk android:minSdkVersion="3"
|
<uses-sdk android:minSdkVersion="7"
|
||||||
android:targetSdkVersion="4"/>
|
android:targetSdkVersion="7"/>
|
||||||
<!-- Donut-specific flags which allow us to run on any dpi screens. -->
|
|
||||||
<supports-screens android:xlargeScreens="true"
|
<supports-screens android:xlargeScreens="true"
|
||||||
android:largeScreens="true"
|
android:largeScreens="true"
|
||||||
android:normalScreens="true"
|
android:normalScreens="true"
|
||||||
|
@ -39,9 +38,6 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="CameraTestActivity"
|
|
||||||
android:screenOrientation="landscape">
|
|
||||||
</activity>
|
|
||||||
<activity android:name="BenchmarkActivity"
|
<activity android:name="BenchmarkActivity"
|
||||||
android:label="@string/benchmark_name"
|
android:label="@string/benchmark_name"
|
||||||
android:screenOrientation="portrait"/>
|
android:screenOrientation="portrait"/>
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
# This file is used to override default values used by the Ant build system.
|
|
||||||
#
|
|
||||||
# This file must be checked in Version Control Systems, as it is
|
|
||||||
# integral to the build system of your project.
|
|
||||||
|
|
||||||
# The name of your application package as defined in the manifest.
|
|
||||||
# Used by the 'uninstall' rule.
|
|
||||||
application-package=com.google.zxing.client.androidtest
|
|
||||||
|
|
||||||
# The name of the source folder.
|
|
||||||
#source-folder=src
|
|
||||||
|
|
||||||
# The name of the output folder.
|
|
||||||
#out-folder=bin
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
# This file is automatically generated by Android Tools.
|
|
||||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
|
||||||
#
|
|
||||||
# This file must be checked in Version Control Systems.
|
|
||||||
#
|
|
||||||
# To customize properties used by the Ant build system use,
|
|
||||||
# "build.properties", and override values to adapt the script to your
|
|
||||||
# project structure.
|
|
||||||
|
|
||||||
# Project target.
|
|
||||||
target=android-10
|
|
|
@ -1,50 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright (C) 2008 ZXing authors
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
|
|
||||||
<SurfaceView android:id="@+id/preview_view"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_centerInParent="true"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:background="@color/transparent">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="@color/transparent"/>
|
|
||||||
|
|
||||||
<TextView android:id="@+id/status_text_view"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="left|center_vertical"
|
|
||||||
android:layout_weight="0"
|
|
||||||
android:text="@string/parameters_message"
|
|
||||||
android:textColor="@color/status_text"
|
|
||||||
android:background="@color/status_view"
|
|
||||||
android:padding="4px"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
|
@ -1,56 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright (C) 2008 ZXing authors
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
|
|
||||||
<SurfaceView android:id="@+id/preview_view"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_centerInParent="true"/>
|
|
||||||
|
|
||||||
<com.google.zxing.client.androidtest.ViewfinderView
|
|
||||||
android:id="@+id/viewfinder_view"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:background="@color/transparent"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:background="@color/transparent">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="@color/transparent"/>
|
|
||||||
|
|
||||||
<TextView android:id="@+id/status_text_view"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="left|center_vertical"
|
|
||||||
android:layout_weight="0"
|
|
||||||
android:text="@string/status_message"
|
|
||||||
android:textColor="@color/status_text"
|
|
||||||
android:background="@color/status_view"
|
|
||||||
android:padding="4px"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
|
@ -20,83 +20,79 @@
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:padding="10px">
|
android:padding="10px">
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<Button android:id="@+id/take_test_photos"
|
<Button android:id="@+id/run_benchmark"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/take_test_photos"/>
|
android:text="@string/benchmark_run"/>
|
||||||
<Button android:id="@+id/get_camera_parameters"
|
<Button android:id="@+id/get_camera_parameters"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/get_camera_parameters"/>
|
android:text="@string/get_camera_parameters"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<Button android:id="@+id/scan_product"
|
<Button android:id="@+id/scan_product"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/scan_product"/>
|
android:text="@string/scan_product"/>
|
||||||
<Button android:id="@+id/scan_qr_code"
|
<Button android:id="@+id/scan_qr_code"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/scan_qr_code"/>
|
android:text="@string/scan_qr_code"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<Button android:id="@+id/scan_anything"
|
<Button android:id="@+id/scan_anything"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/scan_anything"/>
|
android:text="@string/scan_anything"/>
|
||||||
<Button android:id="@+id/search_book_contents"
|
<Button android:id="@+id/search_book_contents"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/search_book_contents"/>
|
android:text="@string/search_book_contents"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<Button android:id="@+id/encode_url"
|
<Button android:id="@+id/encode_url"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/encode_url"/>
|
android:text="@string/encode_url"/>
|
||||||
<Button android:id="@+id/encode_email"
|
<Button android:id="@+id/encode_email"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/encode_email"/>
|
android:text="@string/encode_email"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<Button android:id="@+id/encode_phone"
|
<Button android:id="@+id/encode_phone"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/encode_phone"/>
|
android:text="@string/encode_phone"/>
|
||||||
<Button android:id="@+id/encode_sms"
|
<Button android:id="@+id/encode_sms"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/encode_sms"/>
|
android:text="@string/encode_sms"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<Button android:id="@+id/encode_contact"
|
<Button android:id="@+id/encode_contact"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/encode_contact"/>
|
android:text="@string/encode_contact"/>
|
||||||
<Button android:id="@+id/encode_location"
|
<Button android:id="@+id/encode_location"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/encode_location"/>
|
android:text="@string/encode_location"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<Button android:id="@+id/encode_hidden_data"
|
<Button android:id="@+id/encode_hidden_data"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/encode_hidden_data"/>
|
android:text="@string/encode_hidden_data"/>
|
||||||
<Button android:id="@+id/encode_bad_data"
|
<Button android:id="@+id/encode_bad_data"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/encode_bad_data"/>
|
android:text="@string/encode_bad_data"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<Button android:id="@+id/share_via_barcode"
|
<Button android:id="@+id/share_via_barcode"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/share_via_barcode"/>
|
android:text="@string/share_via_barcode"/>
|
||||||
<Button android:id="@+id/run_benchmark"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/benchmark_run"/>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableLayout>
|
</TableLayout>
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright (C) 2008 ZXing authors
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
<resources>
|
|
||||||
<declare-styleable name="ViewfinderView">
|
|
||||||
</declare-styleable>
|
|
||||||
</resources>
|
|
|
@ -1,289 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2008 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.androidtest;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Point;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.hardware.Camera;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Display;
|
|
||||||
import android.view.SurfaceHolder;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This object wraps the Camera service object and expects to be the only one talking to it. The
|
|
||||||
* implementation encapsulates the steps needed to take preview-sized images, which are used for
|
|
||||||
* both preview and decoding.
|
|
||||||
*
|
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
final class CameraManager {
|
|
||||||
|
|
||||||
private static final String TAG = CameraManager.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final int MIN_FRAME_WIDTH = 240;
|
|
||||||
private static final int MIN_FRAME_HEIGHT = 240;
|
|
||||||
private static final int MAX_FRAME_WIDTH = 480;
|
|
||||||
private static final int MAX_FRAME_HEIGHT = 360;
|
|
||||||
|
|
||||||
private static CameraManager cameraManager;
|
|
||||||
private static final Pattern SEMICOLON = Pattern.compile(";");
|
|
||||||
|
|
||||||
private Camera camera;
|
|
||||||
private final Context context;
|
|
||||||
private Point screenResolution;
|
|
||||||
private Point cameraResolution;
|
|
||||||
private Rect framingRect;
|
|
||||||
private Handler previewHandler;
|
|
||||||
private int previewMessage;
|
|
||||||
private Handler autoFocusHandler;
|
|
||||||
private int autoFocusMessage;
|
|
||||||
private boolean initialized;
|
|
||||||
private boolean previewing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Preview frames are delivered here, which we pass on to the registered handler. Make sure to
|
|
||||||
* clear the handler so it will only receive one message.
|
|
||||||
*/
|
|
||||||
private final Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
|
|
||||||
@Override
|
|
||||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
|
||||||
if (previewHandler != null) {
|
|
||||||
Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x,
|
|
||||||
cameraResolution.y, data);
|
|
||||||
message.sendToTarget();
|
|
||||||
previewHandler = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Autofocus callbacks arrive here, and are dispatched to the Handler which requested them.
|
|
||||||
*/
|
|
||||||
private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
|
|
||||||
@Override
|
|
||||||
public void onAutoFocus(boolean success, Camera camera) {
|
|
||||||
if (autoFocusHandler != null) {
|
|
||||||
Message message = autoFocusHandler.obtainMessage(autoFocusMessage, success);
|
|
||||||
// Barcode Scanner needs to insert a delay here because it does continuous focus,
|
|
||||||
// but this test app does not, so send the message immediately.
|
|
||||||
message.sendToTarget();
|
|
||||||
autoFocusHandler = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes this static object with the Context of the calling Activity.
|
|
||||||
*
|
|
||||||
* @param context The Activity which wants to use the camera.
|
|
||||||
*/
|
|
||||||
public static void init(Context context) {
|
|
||||||
if (cameraManager == null) {
|
|
||||||
cameraManager = new CameraManager(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the CameraManager singleton instance.
|
|
||||||
*
|
|
||||||
* @return A reference to the CameraManager singleton.
|
|
||||||
*/
|
|
||||||
public static CameraManager get() {
|
|
||||||
return cameraManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CameraManager(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
camera = null;
|
|
||||||
initialized = false;
|
|
||||||
previewing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the camera driver and initializes the hardware parameters.
|
|
||||||
*
|
|
||||||
* @param holder The surface object which the camera will draw preview frames into.
|
|
||||||
* @throws IOException Indicates the camera driver failed to open.
|
|
||||||
*/
|
|
||||||
public String openDriver(SurfaceHolder holder, boolean getParameters) throws IOException {
|
|
||||||
String result = null;
|
|
||||||
if (camera == null) {
|
|
||||||
camera = Camera.open();
|
|
||||||
camera.setPreviewDisplay(holder);
|
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
initialized = true;
|
|
||||||
getScreenResolution();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getParameters) {
|
|
||||||
result = collectCameraParameters();
|
|
||||||
}
|
|
||||||
setCameraParameters();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the camera driver if still in use.
|
|
||||||
*/
|
|
||||||
public void closeDriver() {
|
|
||||||
if (camera != null) {
|
|
||||||
camera.release();
|
|
||||||
camera = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asks the camera hardware to begin drawing preview frames to the screen.
|
|
||||||
*/
|
|
||||||
public void startPreview() {
|
|
||||||
if (camera != null && !previewing) {
|
|
||||||
camera.startPreview();
|
|
||||||
previewing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells the camera to stop drawing preview frames.
|
|
||||||
*/
|
|
||||||
public void stopPreview() {
|
|
||||||
if (camera != null && previewing) {
|
|
||||||
camera.stopPreview();
|
|
||||||
previewHandler = null;
|
|
||||||
autoFocusHandler = null;
|
|
||||||
previewing = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
|
|
||||||
* in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
|
|
||||||
* respectively.
|
|
||||||
*
|
|
||||||
* @param handler The handler to send the message to.
|
|
||||||
* @param message The what field of the message to be sent.
|
|
||||||
*/
|
|
||||||
public void requestPreviewFrame(Handler handler, int message) {
|
|
||||||
if (camera != null && previewing) {
|
|
||||||
previewHandler = handler;
|
|
||||||
previewMessage = message;
|
|
||||||
camera.setOneShotPreviewCallback(previewCallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asks the camera hardware to perform an autofocus.
|
|
||||||
*
|
|
||||||
* @param handler The Handler to notify when the autofocus completes.
|
|
||||||
* @param message The message to deliver.
|
|
||||||
*/
|
|
||||||
public void requestAutoFocus(Handler handler, int message) {
|
|
||||||
if (camera != null && previewing) {
|
|
||||||
autoFocusHandler = handler;
|
|
||||||
autoFocusMessage = message;
|
|
||||||
camera.autoFocus(autoFocusCallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the framing rect which the UI should draw to show the user where to place the
|
|
||||||
* barcode. 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) {
|
|
||||||
if (camera == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int width = cameraResolution.x * 3 / 4;
|
|
||||||
if (width < MIN_FRAME_WIDTH) {
|
|
||||||
width = MIN_FRAME_WIDTH;
|
|
||||||
} else if (width > MAX_FRAME_WIDTH) {
|
|
||||||
width = MAX_FRAME_WIDTH;
|
|
||||||
}
|
|
||||||
int height = cameraResolution.y * 3 / 4;
|
|
||||||
if (height < MIN_FRAME_HEIGHT) {
|
|
||||||
height = MIN_FRAME_HEIGHT;
|
|
||||||
} else if (height > MAX_FRAME_HEIGHT) {
|
|
||||||
height = MAX_FRAME_HEIGHT;
|
|
||||||
}
|
|
||||||
int leftOffset = (cameraResolution.x - width) / 2;
|
|
||||||
int topOffset = (cameraResolution.y - height) / 2;
|
|
||||||
framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
|
|
||||||
Log.v(TAG, "Calculated framing rect: " + framingRect);
|
|
||||||
}
|
|
||||||
return framingRect;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the camera up to take preview images which are used for both preview and decoding.
|
|
||||||
* We detect the preview format here so that buildLuminanceSource() can build an appropriate
|
|
||||||
* LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
|
|
||||||
* and the planar Y can be used for barcode scanning without a copy in some cases.
|
|
||||||
*/
|
|
||||||
private void setCameraParameters() {
|
|
||||||
Camera.Parameters parameters = camera.getParameters();
|
|
||||||
Camera.Size size = parameters.getPreviewSize();
|
|
||||||
Log.v(TAG, "Default preview size: " + size.width + ", " + size.height);
|
|
||||||
int previewFormat = parameters.getPreviewFormat();
|
|
||||||
String previewFormatString = parameters.get("preview-format");
|
|
||||||
Log.v(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString);
|
|
||||||
|
|
||||||
// Ensure that the camera resolution is a multiple of 8, as the screen may not be.
|
|
||||||
// IMPORTANT: Do not copy this old code. A much better and more robust solution can be found
|
|
||||||
// in Barcode Scanner under zxing/android.
|
|
||||||
cameraResolution = new Point();
|
|
||||||
cameraResolution.x = (screenResolution.x >> 3) << 3;
|
|
||||||
cameraResolution.y = (screenResolution.y >> 3) << 3;
|
|
||||||
Log.v(TAG, "Setting preview size: " + cameraResolution.x + ", " + cameraResolution.y);
|
|
||||||
parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
|
|
||||||
|
|
||||||
camera.setParameters(parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String collectCameraParameters() {
|
|
||||||
Camera.Parameters parameters = camera.getParameters();
|
|
||||||
String[] params = SEMICOLON.split(parameters.flatten());
|
|
||||||
StringBuilder result = new StringBuilder(100);
|
|
||||||
result.append("Default camera parameters:");
|
|
||||||
for (String param : params) {
|
|
||||||
result.append("\n ");
|
|
||||||
result.append(param);
|
|
||||||
}
|
|
||||||
result.append('\n');
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
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,215 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2008 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.androidtest;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.SurfaceHolder;
|
|
||||||
import android.view.SurfaceView;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public final class CameraTestActivity extends Activity implements SurfaceHolder.Callback {
|
|
||||||
|
|
||||||
private static final String TAG = CameraTestActivity.class.getSimpleName();
|
|
||||||
|
|
||||||
public static final String GET_CAMERA_PARAMETERS = "GET_CAMERA_PARAMETERS";
|
|
||||||
private static final String[] EMAIL_ADDRESS = {"zxing-external@google.com"};
|
|
||||||
|
|
||||||
private SaveThread saveThread;
|
|
||||||
private boolean getCameraParameters;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle icicle) {
|
|
||||||
super.onCreate(icicle);
|
|
||||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
||||||
|
|
||||||
Window window = getWindow();
|
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
|
||||||
|
|
||||||
getCameraParameters = getIntent().getBooleanExtra(GET_CAMERA_PARAMETERS, false);
|
|
||||||
if (getCameraParameters) {
|
|
||||||
setContentView(R.layout.camera_parameters);
|
|
||||||
} else {
|
|
||||||
setContentView(R.layout.camera_test);
|
|
||||||
}
|
|
||||||
CameraManager.init(getApplication());
|
|
||||||
|
|
||||||
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
|
|
||||||
SurfaceHolder surfaceHolder = surfaceView.getHolder();
|
|
||||||
surfaceHolder.addCallback(this);
|
|
||||||
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
if (saveThread == null && !getCameraParameters) {
|
|
||||||
saveThread = new SaveThread(this);
|
|
||||||
saveThread.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
|
|
||||||
CameraManager.get().stopPreview();
|
|
||||||
if (saveThread != null) {
|
|
||||||
Message quit = Message.obtain(saveThread.handler, R.id.quit);
|
|
||||||
quit.sendToTarget();
|
|
||||||
try {
|
|
||||||
saveThread.join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// continue
|
|
||||||
}
|
|
||||||
saveThread = null;
|
|
||||||
}
|
|
||||||
CameraManager.get().closeDriver();
|
|
||||||
}
|
|
||||||
|
|
||||||
final Handler handler = new Handler() {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
switch (message.what) {
|
|
||||||
case R.id.auto_focus:
|
|
||||||
// Do not continuously auto focus
|
|
||||||
break;
|
|
||||||
case R.id.save_succeeded:
|
|
||||||
Toast.makeText(CameraTestActivity.this, R.string.save_succeeded, 500).show();
|
|
||||||
break;
|
|
||||||
case R.id.save_failed:
|
|
||||||
Toast.makeText(CameraTestActivity.this, R.string.save_failed, 2000).show();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
||||||
if (!getCameraParameters) {
|
|
||||||
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
|
|
||||||
if (event.getRepeatCount() == 0) {
|
|
||||||
CameraManager.get().requestAutoFocus(handler, R.id.auto_focus);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else if (keyCode == KeyEvent.KEYCODE_CAMERA || keyCode == KeyEvent.KEYCODE_SEARCH) {
|
|
||||||
if (event.getRepeatCount() == 0) {
|
|
||||||
CameraManager.get().requestPreviewFrame(saveThread.handler, R.id.save);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.onKeyDown(keyCode, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
|
||||||
try {
|
|
||||||
String parameters = CameraManager.get().openDriver(holder, getCameraParameters);
|
|
||||||
CameraManager.get().startPreview();
|
|
||||||
if (getCameraParameters) {
|
|
||||||
collectStatsAndSendEmail(parameters);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private void collectStatsAndSendEmail(String parameters) {
|
|
||||||
StringBuilder result = new StringBuilder(1000);
|
|
||||||
result.append("Device info:");
|
|
||||||
result.append("\n Board: ");
|
|
||||||
result.append(Build.BOARD);
|
|
||||||
result.append("\n Brand: ");
|
|
||||||
result.append(Build.BRAND);
|
|
||||||
result.append("\n Device: ");
|
|
||||||
result.append(Build.DEVICE);
|
|
||||||
result.append("\n Display: ");
|
|
||||||
result.append(Build.DISPLAY);
|
|
||||||
result.append("\n Fingerprint: ");
|
|
||||||
result.append(Build.FINGERPRINT);
|
|
||||||
result.append("\n Host: ");
|
|
||||||
result.append(Build.HOST);
|
|
||||||
result.append("\n ID: ");
|
|
||||||
result.append(Build.ID);
|
|
||||||
result.append("\n Model: ");
|
|
||||||
result.append(Build.MODEL);
|
|
||||||
result.append("\n Product: ");
|
|
||||||
result.append(Build.PRODUCT);
|
|
||||||
result.append("\n Tags: ");
|
|
||||||
result.append(Build.TAGS);
|
|
||||||
result.append("\n Type: ");
|
|
||||||
result.append(Build.TYPE);
|
|
||||||
result.append("\n User: ");
|
|
||||||
result.append(Build.USER);
|
|
||||||
result.append("\n Version Incremental: ");
|
|
||||||
result.append(Build.VERSION.INCREMENTAL);
|
|
||||||
result.append("\n Version Release: ");
|
|
||||||
result.append(Build.VERSION.RELEASE);
|
|
||||||
result.append("\n Version SDK: ");
|
|
||||||
result.append(Build.VERSION.SDK);
|
|
||||||
|
|
||||||
result.append("\n\n");
|
|
||||||
result.append(parameters);
|
|
||||||
|
|
||||||
FileOutputStream stream = null;
|
|
||||||
try {
|
|
||||||
stream = new FileOutputStream(new File("/sdcard/CameraParameters.txt"));
|
|
||||||
stream.write(result.toString().getBytes());
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "Cannot write parameters file ", e);
|
|
||||||
} finally {
|
|
||||||
if (stream != null) {
|
|
||||||
try {
|
|
||||||
stream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
|
||||||
intent.putExtra(Intent.EXTRA_EMAIL, EMAIL_ADDRESS);
|
|
||||||
intent.putExtra(Intent.EXTRA_SUBJECT, "Camera parameters report");
|
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, result.toString());
|
|
||||||
intent.setType("text/plain");
|
|
||||||
startActivity(intent);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2008 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.androidtest;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
final class SaveThread extends Thread {
|
|
||||||
|
|
||||||
private static final String TAG = SaveThread.class.getSimpleName();
|
|
||||||
|
|
||||||
Handler handler;
|
|
||||||
|
|
||||||
private final CameraTestActivity mActivity;
|
|
||||||
|
|
||||||
SaveThread(CameraTestActivity activity) {
|
|
||||||
mActivity = activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Looper.prepare();
|
|
||||||
handler = new Handler() {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
switch (message.what) {
|
|
||||||
case R.id.save:
|
|
||||||
save((byte[]) message.obj, message.arg1, message.arg2);
|
|
||||||
break;
|
|
||||||
case R.id.quit:
|
|
||||||
Looper.myLooper().quit();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Looper.loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the center rectangle of the Y channel as a greyscale PNG to the SD card.
|
|
||||||
private void save(byte[] data, int width, int height) {
|
|
||||||
Rect framingRect = CameraManager.get().getFramingRect();
|
|
||||||
int framingWidth = framingRect.width();
|
|
||||||
int framingHeight = framingRect.height();
|
|
||||||
if (framingWidth > width || framingHeight > height) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
int leftOffset = framingRect.left;
|
|
||||||
int topOffset = framingRect.top;
|
|
||||||
int[] colors = new int[framingWidth * framingHeight];
|
|
||||||
|
|
||||||
for (int y = 0; y < framingHeight; y++) {
|
|
||||||
int rowOffset = (y + topOffset) * width + leftOffset;
|
|
||||||
for (int x = 0; x < framingWidth; x++) {
|
|
||||||
int pixel = (int) data[rowOffset + x];
|
|
||||||
pixel = 0xff000000 + (pixel << 16) + (pixel << 8) + pixel;
|
|
||||||
colors[y * framingWidth + x] = pixel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(colors, framingWidth, framingHeight,
|
|
||||||
Bitmap.Config.ARGB_8888);
|
|
||||||
OutputStream outStream = getNewPhotoOutputStream();
|
|
||||||
if (outStream != null) {
|
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
|
|
||||||
try {
|
|
||||||
outStream.close();
|
|
||||||
Message message = Message.obtain(mActivity.handler, R.id.save_succeeded);
|
|
||||||
message.sendToTarget();
|
|
||||||
return;
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "Exception closing stream: " + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Message message = Message.obtain(mActivity.handler, R.id.save_failed);
|
|
||||||
message.sendToTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static OutputStream getNewPhotoOutputStream() {
|
|
||||||
File sdcard = new File("/sdcard");
|
|
||||||
if (sdcard.exists()) {
|
|
||||||
File barcodes = new File(sdcard, "barcodes");
|
|
||||||
if (barcodes.exists()) {
|
|
||||||
if (!barcodes.isDirectory()) {
|
|
||||||
Log.e(TAG, "/sdcard/barcodes exists but is not a directory");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!barcodes.mkdir()) {
|
|
||||||
Log.e(TAG, "Could not create /sdcard/barcodes directory");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Date now = new Date();
|
|
||||||
String fileName = now.getTime() + ".png";
|
|
||||||
try {
|
|
||||||
return new FileOutputStream(new File(barcodes, fileName));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
Log.e(TAG, "Could not create FileOutputStream");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "/sdcard does not exist");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2008 ZXing authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.client.androidtest;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
public final class ViewfinderView extends View {
|
|
||||||
|
|
||||||
private final Paint paint;
|
|
||||||
private final Rect box;
|
|
||||||
private final int maskColor;
|
|
||||||
private final int frameColor;
|
|
||||||
|
|
||||||
// This constructor is used when the class is built from an XML resource.
|
|
||||||
public ViewfinderView(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
|
|
||||||
// Initialize these once for performance rather than calling them every time in onDraw().
|
|
||||||
paint = new Paint();
|
|
||||||
box = new Rect();
|
|
||||||
Resources resources = getResources();
|
|
||||||
maskColor = resources.getColor(R.color.viewfinder_mask);
|
|
||||||
frameColor = resources.getColor(R.color.viewfinder_frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDraw(Canvas canvas) {
|
|
||||||
Rect frame = CameraManager.get().getFramingRect();
|
|
||||||
int width = canvas.getWidth();
|
|
||||||
int height = canvas.getHeight();
|
|
||||||
|
|
||||||
// Draw the exterior (i.e. outside the framing rect) darkened, in red to distinguish it from
|
|
||||||
// the regular barcodes app
|
|
||||||
paint.setColor(maskColor);
|
|
||||||
box.set(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 white border inside the framing rect
|
|
||||||
paint.setColor(frameColor);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -21,24 +21,36 @@ import android.app.AlertDialog;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.hardware.Camera;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.Contacts;
|
import android.provider.ContactsContract;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import com.google.zxing.integration.android.IntentIntegrator;
|
||||||
|
import com.google.zxing.integration.android.IntentResult;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public final class ZXingTestActivity extends Activity {
|
public final class ZXingTestActivity extends Activity {
|
||||||
|
|
||||||
|
private static final String TAG = ZXingTestActivity.class.getSimpleName();
|
||||||
private static final int ABOUT_ID = Menu.FIRST;
|
private static final int ABOUT_ID = Menu.FIRST;
|
||||||
private static final String PACKAGE_NAME = "com.google.zxing.client.androidtest";
|
private static final String PACKAGE_NAME = ZXingTestActivity.class.getPackage().getName();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
setContentView(R.layout.test);
|
setContentView(R.layout.test);
|
||||||
|
|
||||||
findViewById(R.id.take_test_photos).setOnClickListener(takeTestPhotos);
|
|
||||||
findViewById(R.id.get_camera_parameters).setOnClickListener(getCameraParameters);
|
findViewById(R.id.get_camera_parameters).setOnClickListener(getCameraParameters);
|
||||||
findViewById(R.id.scan_product).setOnClickListener(scanProduct);
|
findViewById(R.id.scan_product).setOnClickListener(scanProduct);
|
||||||
findViewById(R.id.scan_qr_code).setOnClickListener(scanQRCode);
|
findViewById(R.id.scan_qr_code).setOnClickListener(scanQRCode);
|
||||||
|
@ -87,22 +99,29 @@ public final class ZXingTestActivity extends Activity {
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Button.OnClickListener takeTestPhotos = new Button.OnClickListener() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
|
||||||
intent.setClassName(ZXingTestActivity.this, CameraTestActivity.class.getName());
|
if (result != null) {
|
||||||
intent.putExtra(CameraTestActivity.GET_CAMERA_PARAMETERS, false);
|
String contents = result.getContents();
|
||||||
startActivity(intent);
|
if (contents != null) {
|
||||||
|
showDialog(R.string.result_succeeded, "Format: " + result.getFormatName() + "\nContents: " + contents);
|
||||||
|
} else {
|
||||||
|
showDialog(R.string.result_failed, getString(R.string.result_failed_why));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private final Button.OnClickListener getCameraParameters = new Button.OnClickListener() {
|
private final Button.OnClickListener getCameraParameters = new Button.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
String stats = collectStats();
|
||||||
intent.setClassName(ZXingTestActivity.this, CameraTestActivity.class.getName());
|
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||||
intent.putExtra(CameraTestActivity.GET_CAMERA_PARAMETERS, true);
|
intent.putExtra(Intent.EXTRA_EMAIL, "zxing-external@google.com");
|
||||||
|
intent.putExtra(Intent.EXTRA_SUBJECT, "Camera parameters report");
|
||||||
|
intent.putExtra(Intent.EXTRA_TEXT, stats);
|
||||||
|
intent.setType("text/plain");
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -123,24 +142,23 @@ public final class ZXingTestActivity extends Activity {
|
||||||
intent.putExtra("SCAN_MODE", "PRODUCT_MODE");
|
intent.putExtra("SCAN_MODE", "PRODUCT_MODE");
|
||||||
intent.putExtra("SCAN_WIDTH", 800);
|
intent.putExtra("SCAN_WIDTH", 800);
|
||||||
intent.putExtra("SCAN_HEIGHT", 200);
|
intent.putExtra("SCAN_HEIGHT", 200);
|
||||||
startActivityForResult(intent, 0);
|
startActivityForResult(intent, IntentIntegrator.REQUEST_CODE);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final Button.OnClickListener scanQRCode = new Button.OnClickListener() {
|
private final Button.OnClickListener scanQRCode = new Button.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
|
IntentIntegrator integrator = new IntentIntegrator(ZXingTestActivity.this);
|
||||||
intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
|
integrator.initiateScan(IntentIntegrator.QR_CODE_TYPES);
|
||||||
startActivityForResult(intent, 0);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final Button.OnClickListener scanAnything = new Button.OnClickListener() {
|
private final Button.OnClickListener scanAnything = new Button.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
|
IntentIntegrator integrator = new IntentIntegrator(ZXingTestActivity.this);
|
||||||
startActivityForResult(intent, 0);
|
integrator.initiateScan();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -154,19 +172,6 @@ public final class ZXingTestActivity extends Activity {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
|
||||||
if (requestCode == 0) {
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
String contents = intent.getStringExtra("SCAN_RESULT");
|
|
||||||
String format = intent.getStringExtra("SCAN_RESULT_FORMAT");
|
|
||||||
showDialog(R.string.result_succeeded, "Format: " + format + "\nContents: " + contents);
|
|
||||||
} else if (resultCode == RESULT_CANCELED) {
|
|
||||||
showDialog(R.string.result_failed, getString(R.string.result_failed_why));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Button.OnClickListener encodeURL = new Button.OnClickListener() {
|
private final Button.OnClickListener encodeURL = new Button.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -199,10 +204,10 @@ public final class ZXingTestActivity extends Activity {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putString(Contacts.Intents.Insert.NAME, "Jenny");
|
bundle.putString(ContactsContract.Intents.Insert.NAME, "Jenny");
|
||||||
bundle.putString(Contacts.Intents.Insert.PHONE, "8675309");
|
bundle.putString(ContactsContract.Intents.Insert.PHONE, "8675309");
|
||||||
bundle.putString(Contacts.Intents.Insert.EMAIL, "jenny@the80s.com");
|
bundle.putString(ContactsContract.Intents.Insert.EMAIL, "jenny@the80s.com");
|
||||||
bundle.putString(Contacts.Intents.Insert.POSTAL, "123 Fake St. San Francisco, CA 94102");
|
bundle.putString(ContactsContract.Intents.Insert.POSTAL, "123 Fake St. San Francisco, CA 94102");
|
||||||
encodeBarcode("CONTACT_TYPE", bundle);
|
encodeBarcode("CONTACT_TYPE", bundle);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -264,4 +269,75 @@ public final class ZXingTestActivity extends Activity {
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getFlattenedParams() {
|
||||||
|
Camera camera = Camera.open();
|
||||||
|
if (camera == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Camera.Parameters parameters = camera.getParameters();
|
||||||
|
if (parameters == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parameters.flatten();
|
||||||
|
} finally {
|
||||||
|
camera.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String collectStats() {
|
||||||
|
StringBuilder result = new StringBuilder(1000);
|
||||||
|
|
||||||
|
result.append("BOARD=").append(Build.BOARD).append('\n');
|
||||||
|
result.append("BRAND=").append(Build.BRAND).append('\n');
|
||||||
|
result.append("CPU_ABI=").append(Build.CPU_ABI).append('\n');
|
||||||
|
result.append("DEVICE=").append(Build.DEVICE).append('\n');
|
||||||
|
result.append("DISPLAY=").append(Build.DISPLAY).append('\n');
|
||||||
|
result.append("FINGERPRINT=").append(Build.FINGERPRINT).append('\n');
|
||||||
|
result.append("HOST=").append(Build.HOST).append('\n');
|
||||||
|
result.append("ID=").append(Build.ID).append('\n');
|
||||||
|
result.append("MANUFACTURER=").append(Build.MANUFACTURER).append('\n');
|
||||||
|
result.append("MODEL=").append(Build.MODEL).append('\n');
|
||||||
|
result.append("PRODUCT=").append(Build.PRODUCT).append('\n');
|
||||||
|
result.append("TAGS=").append(Build.TAGS).append('\n');
|
||||||
|
result.append("TIME=").append(Build.TIME).append('\n');
|
||||||
|
result.append("TYPE=").append(Build.TYPE).append('\n');
|
||||||
|
result.append("USER=").append(Build.USER).append('\n');
|
||||||
|
result.append("VERSION.CODENAME=").append(Build.VERSION.CODENAME).append('\n');
|
||||||
|
result.append("VERSION.INCREMENTAL=").append(Build.VERSION.INCREMENTAL).append('\n');
|
||||||
|
result.append("VERSION.RELEASE=").append(Build.VERSION.RELEASE).append('\n');
|
||||||
|
result.append("VERSION.SDK_INT=").append(Build.VERSION.SDK_INT).append('\n');
|
||||||
|
|
||||||
|
String flattened = getFlattenedParams();
|
||||||
|
String[] params = flattened.split(";");
|
||||||
|
Arrays.sort(params);
|
||||||
|
for (String param : params) {
|
||||||
|
result.append(param).append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
String resultString = result.toString();
|
||||||
|
writeStats(resultString);
|
||||||
|
|
||||||
|
return resultString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeStats(String resultString) {
|
||||||
|
Writer out = null;
|
||||||
|
try {
|
||||||
|
out = new OutputStreamWriter(new FileOutputStream(new File("/sdcard/CameraParameters.txt")),
|
||||||
|
Charset.forName("UTF-8"));
|
||||||
|
out.write(resultString);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Cannot write parameters file ", e);
|
||||||
|
} finally {
|
||||||
|
if (out != null) {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,9 +130,7 @@
|
||||||
<target name="clean">
|
<target name="clean">
|
||||||
<delete dir="build"/>
|
<delete dir="build"/>
|
||||||
<delete dir="build-test"/>
|
<delete dir="build-test"/>
|
||||||
<delete dir="optimized"/>
|
|
||||||
<delete file="core.jar"/>
|
<delete file="core.jar"/>
|
||||||
<delete file="ZXingReader.*"/>
|
|
||||||
<delete file="proguard-dump.txt"/>
|
<delete file="proguard-dump.txt"/>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<artifactId>core</artifactId>
|
<artifactId>core</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>ZXing Core</name>
|
<name>ZXing Core</name>
|
||||||
<version>1.6-SNAPSHOT</version>
|
<version>2.0-SNAPSHOT</version>
|
||||||
<description>Core barcode encoding/decoding library</description>
|
<description>Core barcode encoding/decoding library</description>
|
||||||
<url>http://code.google.com/p/zxing</url>
|
<url>http://code.google.com/p/zxing</url>
|
||||||
<inceptionYear>2007</inceptionYear>
|
<inceptionYear>2007</inceptionYear>
|
||||||
|
|
Loading…
Reference in a new issue