Issue 835: Added support for specifying a width and height for the scanning rectangle when launching Barcode Scanner by Intent.

git-svn-id: https://zxing.googlecode.com/svn/trunk@1776 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
dswitkin@google.com 2011-05-17 19:20:38 +00:00
parent 8ff9e7f4fa
commit e3e0a12da8
6 changed files with 118 additions and 76 deletions

View file

@ -194,6 +194,13 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
// Scan the formats the intent requested, and return the result to the calling activity. // Scan the formats the intent requested, and return the result to the calling activity.
source = Source.NATIVE_APP_INTENT; source = Source.NATIVE_APP_INTENT;
decodeFormats = DecodeFormatManager.parseDecodeFormats(intent); decodeFormats = DecodeFormatManager.parseDecodeFormats(intent);
if (intent.hasExtra(Intents.Scan.WIDTH) && intent.hasExtra(Intents.Scan.HEIGHT)) {
int width = intent.getIntExtra(Intents.Scan.WIDTH, 0);
int height = intent.getIntExtra(Intents.Scan.HEIGHT, 0);
if (width > 0 && height > 0) {
CameraManager.get().setManualFramingRect(width, height);
}
}
} else if (dataString != null && dataString.contains(PRODUCT_SEARCH_URL_PREFIX) && } else if (dataString != null && dataString.contains(PRODUCT_SEARCH_URL_PREFIX) &&
dataString.contains(PRODUCT_SEARCH_URL_SUFFIX)) { dataString.contains(PRODUCT_SEARCH_URL_SUFFIX)) {
// Scan only products and send the result to mobile Product Search. // Scan only products and send the result to mobile Product Search.

View file

@ -56,7 +56,7 @@ final class DecodeFormatManager {
static Vector<BarcodeFormat> parseDecodeFormats(Intent intent) { static Vector<BarcodeFormat> parseDecodeFormats(Intent intent) {
List<String> scanFormats = null; List<String> scanFormats = null;
String scanFormatsString = intent.getStringExtra(Intents.Scan.SCAN_FORMATS); String scanFormatsString = intent.getStringExtra(Intents.Scan.FORMATS);
if (scanFormatsString != null) { if (scanFormatsString != null) {
scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString)); scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString));
} }
@ -64,7 +64,7 @@ final class DecodeFormatManager {
} }
static Vector<BarcodeFormat> parseDecodeFormats(Uri inputUri) { static Vector<BarcodeFormat> parseDecodeFormats(Uri inputUri) {
List<String> formats = inputUri.getQueryParameters(Intents.Scan.SCAN_FORMATS); List<String> formats = inputUri.getQueryParameters(Intents.Scan.FORMATS);
if (formats != null && formats.size() == 1 && formats.get(0) != null){ if (formats != null && formats.size() == 1 && formats.get(0) != null){
formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0))); formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0)));
} }

View file

@ -49,7 +49,6 @@ final class DecodeHandler extends Handler {
public void handleMessage(Message message) { public void handleMessage(Message message) {
switch (message.what) { switch (message.what) {
case R.id.decode: case R.id.decode:
//Log.d(TAG, "Got decode message");
decode((byte[]) message.obj, message.arg1, message.arg2); decode((byte[]) message.obj, message.arg1, message.arg2);
break; break;
case R.id.quit: case R.id.quit:
@ -86,7 +85,6 @@ final class DecodeHandler extends Handler {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap()); bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
message.setData(bundle); message.setData(bundle);
//Log.d(TAG, "Sending decode succeeded message...");
message.sendToTarget(); message.sendToTarget();
} else { } else {
Message message = Message.obtain(activity.getHandler(), R.id.decode_failed); Message message = Message.obtain(activity.getHandler(), R.id.decode_failed);

View file

@ -36,28 +36,13 @@ public final class Intents {
/** /**
* By default, sending Scan.ACTION will decode all barcodes that we understand. However it * By default, sending Scan.ACTION will decode all barcodes that we understand. However it
* may be useful to limit scanning to certain formats. Use Intent.putExtra(MODE, value) with * may be useful to limit scanning to certain formats. Use Intent.putExtra(MODE, value) with
* one of the values below ({@link #PRODUCT_MODE}, {@link #ONE_D_MODE}, {@link #QR_CODE_MODE}). * one of the values below.
* Optional.
* *
* Setting this is effectively shorthnad for setting explicit formats with {@link #SCAN_FORMATS}. * Setting this is effectively shorthand for setting explicit formats with {@link #FORMATS}.
* It is overridden by that setting. * It is overridden by that setting.
*/ */
public static final String MODE = "SCAN_MODE"; public static final String MODE = "SCAN_MODE";
/**
* Comma-separated list of formats to scan for. The values must match the names of
* {@link com.google.zxing.BarcodeFormat}s, such as {@link com.google.zxing.BarcodeFormat#EAN_13}.
* Example: "EAN_13,EAN_8,QR_CODE"
*
* This overrides {@link #MODE}.
*/
public static final String SCAN_FORMATS = "SCAN_FORMATS";
/**
* @see com.google.zxing.DecodeHintType#CHARACTER_SET
*/
public static final String CHARACTER_SET = "CHARACTER_SET";
/** /**
* Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get * Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get
* prices, reviews, etc. for products. * prices, reviews, etc. for products.
@ -65,7 +50,7 @@ public final class Intents {
public static final String PRODUCT_MODE = "PRODUCT_MODE"; public static final String PRODUCT_MODE = "PRODUCT_MODE";
/** /**
* Decode only 1D barcodes (currently UPC, EAN, Code 39, and Code 128). * Decode only 1D barcodes.
*/ */
public static final String ONE_D_MODE = "ONE_D_MODE"; public static final String ONE_D_MODE = "ONE_D_MODE";
@ -79,6 +64,28 @@ public final class Intents {
*/ */
public static final String DATA_MATRIX_MODE = "DATA_MATRIX_MODE"; public static final String DATA_MATRIX_MODE = "DATA_MATRIX_MODE";
/**
* Comma-separated list of formats to scan for. The values must match the names of
* {@link com.google.zxing.BarcodeFormat}s, e.g. {@link com.google.zxing.BarcodeFormat#EAN_13}.
* Example: "EAN_13,EAN_8,QR_CODE"
*
* This overrides {@link #MODE}.
*/
public static final String FORMATS = "SCAN_FORMATS";
/**
* @see com.google.zxing.DecodeHintType#CHARACTER_SET
*/
public static final String CHARACTER_SET = "CHARACTER_SET";
/**
* Optional parameters to specify the width and height of the scanning rectangle in pixels.
* The app will try to honor these, but will clamp them to the size of the preview frame.
* You should specify both or neither, and pass the size as an int.
*/
public static final String WIDTH = "SCAN_WIDTH";
public static final String HEIGHT = "SCAN_HEIGHT";
/** /**
* If a barcode is found, Barcodes returns RESULT_OK to onActivityResult() of the app which * If a barcode is found, Barcodes returns RESULT_OK to onActivityResult() of the app which
* requested the scan via startSubActivity(). The barcodes contents can be retrieved with * requested the scan via startSubActivity(). The barcodes contents can be retrieved with
@ -127,11 +134,11 @@ public final class Intents {
* Intent.putExtra(TYPE, type) with one of Contents.Type. * Intent.putExtra(TYPE, type) with one of Contents.Type.
*/ */
public static final String TYPE = "ENCODE_TYPE"; public static final String TYPE = "ENCODE_TYPE";
/** /**
* The barcode format to be displayed. If this isn't specified or is blank, * The barcode format to be displayed. If this isn't specified or is blank,
* it defaults to QR Code. Use Intent.putExtra(FORMAT, format), where * it defaults to QR Code. Use Intent.putExtra(FORMAT, format), where
* format is one of Contents.Format. * format is one of Contents.Format.
*/ */
public static final String FORMAT = "ENCODE_FORMAT"; public static final String FORMAT = "ENCODE_FORMAT";
@ -160,30 +167,29 @@ public final class Intents {
} }
public static final class WifiConnect { public static final class WifiConnect {
/** /**
* Internal intent used to trigger connection to a wi-fi network. * Internal intent used to trigger connection to a wi-fi network.
*/ */
public static final String ACTION = "com.google.zxing.client.android.WIFI_CONNECT"; public static final String ACTION = "com.google.zxing.client.android.WIFI_CONNECT";
/** /**
* The network to connect to, all the configuration provided here. * The network to connect to, all the configuration provided here.
*/ */
public static final String SSID = "SSID"; public static final String SSID = "SSID";
/** /**
* The network to connect to, all the configuration provided here. * The network to connect to, all the configuration provided here.
*/ */
public static final String TYPE = "TYPE"; public static final String TYPE = "TYPE";
/** /**
* The network to connect to, all the configuration provided here. * The network to connect to, all the configuration provided here.
*/ */
public static final String PASSWORD = "PASSWORD"; public static final String PASSWORD = "PASSWORD";
private WifiConnect() {
}
}
private WifiConnect() {
}
}
public static final class Share { public static final class Share {
/** /**

View file

@ -148,6 +148,11 @@ public final class CameraManager {
FlashlightManager.disableFlashlight(); FlashlightManager.disableFlashlight();
camera.release(); camera.release();
camera = null; camera = null;
// Make sure to clear these each time we close the camera, so that any scanning rect
// requested by intent is forgotten.
framingRect = null;
framingRectInPreview = null;
} }
} }
@ -217,11 +222,11 @@ public final class CameraManager {
* @return The rectangle to draw on screen in window coordinates. * @return The rectangle to draw on screen in window coordinates.
*/ */
public Rect getFramingRect() { public Rect getFramingRect() {
Point screenResolution = configManager.getScreenResolution();
if (framingRect == null) { if (framingRect == null) {
if (camera == null) { if (camera == null) {
return null; return null;
} }
Point screenResolution = configManager.getScreenResolution();
int width = screenResolution.x * 3 / 4; int width = screenResolution.x * 3 / 4;
if (width < MIN_FRAME_WIDTH) { if (width < MIN_FRAME_WIDTH) {
width = MIN_FRAME_WIDTH; width = MIN_FRAME_WIDTH;
@ -260,6 +265,28 @@ public final class CameraManager {
return framingRectInPreview; return framingRectInPreview;
} }
/**
* Allows third party apps to specify the scanning rectangle dimensions, rather than determine
* them automatically based on screen resolution.
*
* @param width The width in pixels to scan.
* @param height The height in pixels to scan.
*/
public void setManualFramingRect(int width, int height) {
Point screenResolution = configManager.getScreenResolution();
if (width > screenResolution.x) {
width = screenResolution.x;
}
if (height > screenResolution.y) {
height = screenResolution.y;
}
int leftOffset = (screenResolution.x - width) / 2;
int topOffset = (screenResolution.y - height) / 2;
framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
Log.d(TAG, "Calculated manual framing rect: " + framingRect);
framingRectInPreview = null;
}
/** /**
* A factory method to build the appropriate LuminanceSource object based on the format * A factory method to build the appropriate LuminanceSource object based on the format
* of the preview buffers, as described by Camera.Parameters. * of the preview buffers, as described by Camera.Parameters.
@ -273,6 +300,8 @@ public final class CameraManager {
Rect rect = getFramingRectInPreview(); Rect rect = getFramingRectInPreview();
int previewFormat = configManager.getPreviewFormat(); int previewFormat = configManager.getPreviewFormat();
String previewFormatString = configManager.getPreviewFormatString(); String previewFormatString = configManager.getPreviewFormatString();
// FIXME(dswitkin): Don't access the preferences on every scan, this is expensive!
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean reverseImage = sharedPrefs.getBoolean(PreferencesActivity.KEY_REVERSE_IMAGE, false); boolean reverseImage = sharedPrefs.getBoolean(PreferencesActivity.KEY_REVERSE_IMAGE, false);

View file

@ -38,21 +38,21 @@ public final class ZXingTestActivity extends Activity {
super.onCreate(icicle); super.onCreate(icicle);
setContentView(R.layout.test); setContentView(R.layout.test);
findViewById(R.id.take_test_photos).setOnClickListener(mTakeTestPhotos); findViewById(R.id.take_test_photos).setOnClickListener(takeTestPhotos);
findViewById(R.id.get_camera_parameters).setOnClickListener(mGetCameraParameters); findViewById(R.id.get_camera_parameters).setOnClickListener(getCameraParameters);
findViewById(R.id.run_benchmark).setOnClickListener(mRunBenchmark); findViewById(R.id.run_benchmark).setOnClickListener(runBenchmark);
findViewById(R.id.scan_product).setOnClickListener(mScanProduct); findViewById(R.id.scan_product).setOnClickListener(scanProduct);
findViewById(R.id.scan_qr_code).setOnClickListener(mScanQRCode); findViewById(R.id.scan_qr_code).setOnClickListener(scanQRCode);
findViewById(R.id.scan_anything).setOnClickListener(mScanAnything); findViewById(R.id.scan_anything).setOnClickListener(scanAnything);
findViewById(R.id.search_book_contents).setOnClickListener(mSearchBookContents); findViewById(R.id.search_book_contents).setOnClickListener(searchBookContents);
findViewById(R.id.encode_url).setOnClickListener(mEncodeURL); findViewById(R.id.encode_url).setOnClickListener(encodeURL);
findViewById(R.id.encode_email).setOnClickListener(mEncodeEmail); findViewById(R.id.encode_email).setOnClickListener(encodeEmail);
findViewById(R.id.encode_phone).setOnClickListener(mEncodePhone); findViewById(R.id.encode_phone).setOnClickListener(encodePhone);
findViewById(R.id.encode_sms).setOnClickListener(mEncodeSMS); findViewById(R.id.encode_sms).setOnClickListener(encodeSMS);
findViewById(R.id.encode_contact).setOnClickListener(mEncodeContact); findViewById(R.id.encode_contact).setOnClickListener(encodeContact);
findViewById(R.id.encode_location).setOnClickListener(mEncodeLocation); findViewById(R.id.encode_location).setOnClickListener(encodeLocation);
findViewById(R.id.encode_bad_data).setOnClickListener(mEncodeBadData); findViewById(R.id.encode_bad_data).setOnClickListener(encodeBadData);
findViewById(R.id.share_via_barcode).setOnClickListener(mShareViaBarcode); findViewById(R.id.share_via_barcode).setOnClickListener(shareViaBarcode);
} }
@Override @Override
@ -86,7 +86,7 @@ public final class ZXingTestActivity extends Activity {
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
public final Button.OnClickListener mTakeTestPhotos = new Button.OnClickListener() { public final Button.OnClickListener takeTestPhotos = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW); Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClassName(ZXingTestActivity.this, CameraTestActivity.class.getName()); intent.setClassName(ZXingTestActivity.this, CameraTestActivity.class.getName());
@ -95,7 +95,7 @@ public final class ZXingTestActivity extends Activity {
} }
}; };
public final Button.OnClickListener mGetCameraParameters = new Button.OnClickListener() { public final Button.OnClickListener getCameraParameters = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW); Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClassName(ZXingTestActivity.this, CameraTestActivity.class.getName()); intent.setClassName(ZXingTestActivity.this, CameraTestActivity.class.getName());
@ -104,7 +104,7 @@ public final class ZXingTestActivity extends Activity {
} }
}; };
public final Button.OnClickListener mRunBenchmark = new Button.OnClickListener() { public final Button.OnClickListener runBenchmark = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW); Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClassName(ZXingTestActivity.this, BenchmarkActivity.class.getName()); intent.setClassName(ZXingTestActivity.this, BenchmarkActivity.class.getName());
@ -112,15 +112,17 @@ public final class ZXingTestActivity extends Activity {
} }
}; };
public final Button.OnClickListener mScanProduct = new Button.OnClickListener() { public final Button.OnClickListener scanProduct = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
Intent intent = new Intent("com.google.zxing.client.android.SCAN"); Intent intent = new Intent("com.google.zxing.client.android.SCAN");
intent.putExtra("SCAN_MODE", "PRODUCT_MODE"); intent.putExtra("SCAN_MODE", "PRODUCT_MODE");
intent.putExtra("SCAN_WIDTH", 800);
intent.putExtra("SCAN_HEIGHT", 200);
startActivityForResult(intent, 0); startActivityForResult(intent, 0);
} }
}; };
public final Button.OnClickListener mScanQRCode = new Button.OnClickListener() { public final Button.OnClickListener scanQRCode = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
Intent intent = new Intent("com.google.zxing.client.android.SCAN"); Intent intent = new Intent("com.google.zxing.client.android.SCAN");
intent.putExtra("SCAN_MODE", "QR_CODE_MODE"); intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
@ -128,14 +130,14 @@ public final class ZXingTestActivity extends Activity {
} }
}; };
public final Button.OnClickListener mScanAnything = new Button.OnClickListener() { public final Button.OnClickListener scanAnything = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
Intent intent = new Intent("com.google.zxing.client.android.SCAN"); Intent intent = new Intent("com.google.zxing.client.android.SCAN");
startActivityForResult(intent, 0); startActivityForResult(intent, 0);
} }
}; };
public final Button.OnClickListener mSearchBookContents = new Button.OnClickListener() { public final Button.OnClickListener searchBookContents = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
Intent intent = new Intent("com.google.zxing.client.android.SEARCH_BOOK_CONTENTS"); Intent intent = new Intent("com.google.zxing.client.android.SEARCH_BOOK_CONTENTS");
intent.putExtra("ISBN", "9780441014989"); intent.putExtra("ISBN", "9780441014989");
@ -157,31 +159,31 @@ public final class ZXingTestActivity extends Activity {
} }
} }
public final Button.OnClickListener mEncodeURL = new Button.OnClickListener() { public final Button.OnClickListener encodeURL = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
encodeBarcode("TEXT_TYPE", "http://www.nytimes.com"); encodeBarcode("TEXT_TYPE", "http://www.nytimes.com");
} }
}; };
public final Button.OnClickListener mEncodeEmail = new Button.OnClickListener() { public final Button.OnClickListener encodeEmail = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
encodeBarcode("EMAIL_TYPE", "foo@example.com"); encodeBarcode("EMAIL_TYPE", "foo@example.com");
} }
}; };
public final Button.OnClickListener mEncodePhone = new Button.OnClickListener() { public final Button.OnClickListener encodePhone = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
encodeBarcode("PHONE_TYPE", "2125551212"); encodeBarcode("PHONE_TYPE", "2125551212");
} }
}; };
public final Button.OnClickListener mEncodeSMS = new Button.OnClickListener() { public final Button.OnClickListener encodeSMS = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
encodeBarcode("SMS_TYPE", "2125551212"); encodeBarcode("SMS_TYPE", "2125551212");
} }
}; };
public final Button.OnClickListener mEncodeContact = new Button.OnClickListener() { public final Button.OnClickListener encodeContact = new Button.OnClickListener() {
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(Contacts.Intents.Insert.NAME, "Jenny");
@ -192,7 +194,7 @@ public final class ZXingTestActivity extends Activity {
} }
}; };
public final Button.OnClickListener mEncodeLocation = new Button.OnClickListener() { public final Button.OnClickListener encodeLocation = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putFloat("LAT", 40.829208f); bundle.putFloat("LAT", 40.829208f);
@ -201,13 +203,13 @@ public final class ZXingTestActivity extends Activity {
} }
}; };
public final Button.OnClickListener mEncodeBadData = new Button.OnClickListener() { public final Button.OnClickListener encodeBadData = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
encodeBarcode(null, "bar"); encodeBarcode(null, "bar");
} }
}; };
public final Button.OnClickListener mShareViaBarcode = new Button.OnClickListener() { public final Button.OnClickListener shareViaBarcode = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
startActivity(new Intent("com.google.zxing.client.android.SHARE")); startActivity(new Intent("com.google.zxing.client.android.SHARE"));
} }