mirror of
https://github.com/zxing/zxing.git
synced 2025-01-12 19:57:27 -08:00
Lots of updates:
- Added support for new YUYV preview buffer format. - Made the preview rectangle larger. - Added support for high resolution screens. - Updated for Donut but still runs on Cupcake. - Converted to standard Java coding style for member variables. - Added many comments and author tags. - Removed some Petit Four hacks and vestigial code. *** The app must be built with the Donut SDK from now on. git-svn-id: https://zxing.googlecode.com/svn/trunk@1049 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
e83cb0cef1
commit
833ca52c27
|
@ -20,9 +20,16 @@ version to be published. The next versionCode will be 7, regardless of whether t
|
||||||
versionName is 2.31, 2.4, or 3.0. -->
|
versionName is 2.31, 2.4, or 3.0. -->
|
||||||
<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.android"
|
package="com.google.zxing.client.android"
|
||||||
android:versionName="2.93"
|
android:versionName="3.0 alpha1"
|
||||||
android:versionCode="30">
|
android:versionCode="32">
|
||||||
|
<!-- Allows this app to run on Cupcake devices. -->
|
||||||
<uses-sdk android:minSdkVersion="3"/>
|
<uses-sdk android:minSdkVersion="3"/>
|
||||||
|
<!-- Donut-specific flags which allow us to run on large and high dpi screens. -->
|
||||||
|
<supports-screens
|
||||||
|
android:largeScreens="true"
|
||||||
|
android:normalScreens="true"
|
||||||
|
android:smallScreens="true"
|
||||||
|
android:anyDensity="true"/>
|
||||||
<application android:icon="@drawable/launcher_icon"
|
<application android:icon="@drawable/launcher_icon"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<activity android:name=".CaptureActivity"
|
<activity android:name=".CaptureActivity"
|
||||||
|
|
|
@ -8,4 +8,4 @@
|
||||||
# project structure.
|
# project structure.
|
||||||
|
|
||||||
# Project target.
|
# Project target.
|
||||||
target=Google Inc.:Google APIs:3
|
target=Google Inc.:Google APIs:4
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2009 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.android;
|
||||||
|
|
||||||
|
import com.google.zxing.LuminanceSource;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An extension of LuminanceSource which adds some Android-specific methods.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
public abstract class BaseLuminanceSource extends LuminanceSource {
|
||||||
|
public BaseLuminanceSource(int width, int height) {
|
||||||
|
super(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests the width of the underlying platform's bitmap.
|
||||||
|
*
|
||||||
|
* @return The width in pixels.
|
||||||
|
*/
|
||||||
|
public abstract int getDataWidth();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests the height of the underlying platform's bitmap.
|
||||||
|
*
|
||||||
|
* @return The height in pixels.
|
||||||
|
*/
|
||||||
|
public abstract int getDataHeight();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a greyscale Android Bitmap from the YUV data based on the crop rectangle.
|
||||||
|
*
|
||||||
|
* @return An 8888 bitmap.
|
||||||
|
*/
|
||||||
|
public abstract Bitmap renderCroppedGreyscaleBitmap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a color Android Bitmap from the YUV data, ignoring the crop rectangle.
|
||||||
|
*
|
||||||
|
* @param halfSize If true, downsample to 50% in each dimension, otherwise not.
|
||||||
|
* @return An 8888 bitmap.
|
||||||
|
*/
|
||||||
|
public abstract Bitmap renderFullColorBitmap(boolean halfSize);
|
||||||
|
}
|
|
@ -29,9 +29,10 @@ import android.widget.SimpleCursorAdapter;
|
||||||
/**
|
/**
|
||||||
* This class is only needed because I can't successfully send an ACTION_PICK intent to
|
* This class is only needed because I can't successfully send an ACTION_PICK intent to
|
||||||
* com.android.browser.BrowserBookmarksPage. It can go away if that starts working in the future.
|
* com.android.browser.BrowserBookmarksPage. It can go away if that starts working in the future.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
*/
|
*/
|
||||||
public final class BookmarkPickerActivity extends ListActivity {
|
public final class BookmarkPickerActivity extends ListActivity {
|
||||||
|
|
||||||
private static final String[] BOOKMARK_PROJECTION = {
|
private static final String[] BOOKMARK_PROJECTION = {
|
||||||
Browser.BookmarkColumns.TITLE,
|
Browser.BookmarkColumns.TITLE,
|
||||||
Browser.BookmarkColumns.URL
|
Browser.BookmarkColumns.URL
|
||||||
|
@ -48,32 +49,31 @@ public final class BookmarkPickerActivity extends ListActivity {
|
||||||
// Without this selection, we'd get all the history entries too
|
// Without this selection, we'd get all the history entries too
|
||||||
private static final String BOOKMARK_SELECTION = "bookmark = 1";
|
private static final String BOOKMARK_SELECTION = "bookmark = 1";
|
||||||
|
|
||||||
private Cursor mCursor;
|
private Cursor cursor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle icicle) {
|
protected void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
|
|
||||||
mCursor = getContentResolver().query(Browser.BOOKMARKS_URI, BOOKMARK_PROJECTION,
|
cursor = getContentResolver().query(Browser.BOOKMARKS_URI, BOOKMARK_PROJECTION,
|
||||||
BOOKMARK_SELECTION, null, null);
|
BOOKMARK_SELECTION, null, null);
|
||||||
startManagingCursor(mCursor);
|
startManagingCursor(cursor);
|
||||||
|
|
||||||
ListAdapter adapter = new SimpleCursorAdapter(this, R.layout.bookmark_picker_list_item,
|
ListAdapter adapter = new SimpleCursorAdapter(this, R.layout.bookmark_picker_list_item,
|
||||||
mCursor, BOOKMARK_PROJECTION, TWO_LINE_VIEW_IDS);
|
cursor, BOOKMARK_PROJECTION, TWO_LINE_VIEW_IDS);
|
||||||
setListAdapter(adapter);
|
setListAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onListItemClick(ListView l, View view, int position, long id) {
|
protected void onListItemClick(ListView l, View view, int position, long id) {
|
||||||
if (mCursor.moveToPosition(position)) {
|
if (cursor.moveToPosition(position)) {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.putExtra(Browser.BookmarkColumns.TITLE, mCursor.getString(TITLE_COLUMN));
|
intent.putExtra(Browser.BookmarkColumns.TITLE, cursor.getString(TITLE_COLUMN));
|
||||||
intent.putExtra(Browser.BookmarkColumns.URL, mCursor.getString(URL_COLUMN));
|
intent.putExtra(Browser.BookmarkColumns.URL, cursor.getString(URL_COLUMN));
|
||||||
setResult(RESULT_OK, intent);
|
setResult(RESULT_OK, intent);
|
||||||
} else {
|
} else {
|
||||||
setResult(RESULT_CANCELED);
|
setResult(RESULT_CANCELED);
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package com.google.zxing.client.android;
|
||||||
import com.google.zxing.ResultPoint;
|
import com.google.zxing.ResultPoint;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.hardware.Camera;
|
import android.hardware.Camera;
|
||||||
|
@ -35,47 +36,82 @@ import java.io.IOException;
|
||||||
* This object wraps the Camera service object and expects to be the only one talking to it. The
|
* 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
|
* implementation encapsulates the steps needed to take preview-sized images, which are used for
|
||||||
* both preview and decoding.
|
* both preview and decoding.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
*/
|
*/
|
||||||
final class CameraManager {
|
final class CameraManager {
|
||||||
|
|
||||||
private static final String TAG = "CameraManager";
|
private static final String TAG = "CameraManager";
|
||||||
|
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 mCameraManager;
|
private static CameraManager cameraManager;
|
||||||
private Camera mCamera;
|
private Camera camera;
|
||||||
private final Context mContext;
|
private final Context context;
|
||||||
private Point mScreenResolution;
|
private Point screenResolution;
|
||||||
private Rect mFramingRect;
|
private Point cameraResolution;
|
||||||
private Handler mPreviewHandler;
|
private Rect framingRect;
|
||||||
private int mPreviewMessage;
|
private Handler previewHandler;
|
||||||
private Handler mAutoFocusHandler;
|
private int previewMessage;
|
||||||
private int mAutoFocusMessage;
|
private Handler autoFocusHandler;
|
||||||
private boolean mInitialized;
|
private int autoFocusMessage;
|
||||||
private boolean mPreviewing;
|
private boolean initialized;
|
||||||
|
private boolean previewing;
|
||||||
|
private int previewFormat;
|
||||||
|
private String previewFormatString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preview frames are delivered here, which we pass on to the registered handler. Make sure to
|
||||||
|
* clear the handler so it will only receive one message.
|
||||||
|
*/
|
||||||
|
private final Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
|
||||||
|
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||||
|
camera.setPreviewCallback(null);
|
||||||
|
if (previewHandler != null) {
|
||||||
|
Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x,
|
||||||
|
cameraResolution.y, data);
|
||||||
|
message.sendToTarget();
|
||||||
|
previewHandler = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
|
||||||
|
public void onAutoFocus(boolean success, Camera camera) {
|
||||||
|
if (autoFocusHandler != null) {
|
||||||
|
Message message = autoFocusHandler.obtainMessage(autoFocusMessage, success);
|
||||||
|
// Simulate continuous autofocus by sending a focus request every 1.5 seconds.
|
||||||
|
autoFocusHandler.sendMessageDelayed(message, 1500L);
|
||||||
|
autoFocusHandler = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public static void init(Context context) {
|
public static void init(Context context) {
|
||||||
if (mCameraManager == null) {
|
if (cameraManager == null) {
|
||||||
mCameraManager = new CameraManager(context);
|
cameraManager = new CameraManager(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CameraManager get() {
|
public static CameraManager get() {
|
||||||
return mCameraManager;
|
return cameraManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CameraManager(Context context) {
|
private CameraManager(Context context) {
|
||||||
mContext = context;
|
this.context = context;
|
||||||
mCamera = null;
|
camera = null;
|
||||||
mInitialized = false;
|
initialized = false;
|
||||||
mPreviewing = false;
|
previewing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openDriver(SurfaceHolder holder) throws IOException {
|
public void openDriver(SurfaceHolder holder) throws IOException {
|
||||||
if (mCamera == null) {
|
if (camera == null) {
|
||||||
mCamera = Camera.open();
|
camera = Camera.open();
|
||||||
mCamera.setPreviewDisplay(holder);
|
camera.setPreviewDisplay(holder);
|
||||||
|
|
||||||
if (!mInitialized) {
|
if (!initialized) {
|
||||||
mInitialized = true;
|
initialized = true;
|
||||||
getScreenResolution();
|
getScreenResolution();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,26 +120,26 @@ final class CameraManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeDriver() {
|
public void closeDriver() {
|
||||||
if (mCamera != null) {
|
if (camera != null) {
|
||||||
mCamera.release();
|
camera.release();
|
||||||
mCamera = null;
|
camera = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startPreview() {
|
public void startPreview() {
|
||||||
if (mCamera != null && !mPreviewing) {
|
if (camera != null && !previewing) {
|
||||||
mCamera.startPreview();
|
camera.startPreview();
|
||||||
mPreviewing = true;
|
previewing = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopPreview() {
|
public void stopPreview() {
|
||||||
if (mCamera != null && mPreviewing) {
|
if (camera != null && previewing) {
|
||||||
mCamera.setPreviewCallback(null);
|
camera.setPreviewCallback(null);
|
||||||
mCamera.stopPreview();
|
camera.stopPreview();
|
||||||
mPreviewHandler = null;
|
previewHandler = null;
|
||||||
mAutoFocusHandler = null;
|
autoFocusHandler = null;
|
||||||
mPreviewing = false;
|
previewing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,39 +152,48 @@ final class CameraManager {
|
||||||
* @param message The what field of the message to be sent.
|
* @param message The what field of the message to be sent.
|
||||||
*/
|
*/
|
||||||
public void requestPreviewFrame(Handler handler, int message) {
|
public void requestPreviewFrame(Handler handler, int message) {
|
||||||
if (mCamera != null && mPreviewing) {
|
if (camera != null && previewing) {
|
||||||
mPreviewHandler = handler;
|
previewHandler = handler;
|
||||||
mPreviewMessage = message;
|
previewMessage = message;
|
||||||
mCamera.setPreviewCallback(previewCallback);
|
camera.setPreviewCallback(previewCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestAutoFocus(Handler handler, int message) {
|
public void requestAutoFocus(Handler handler, int message) {
|
||||||
if (mCamera != null && mPreviewing) {
|
if (camera != null && previewing) {
|
||||||
mAutoFocusHandler = handler;
|
autoFocusHandler = handler;
|
||||||
mAutoFocusMessage = message;
|
autoFocusMessage = message;
|
||||||
mCamera.autoFocus(autoFocusCallback);
|
camera.autoFocus(autoFocusCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the framing rect which the UI should draw to show the user where to place the
|
* Calculates the framing rect which the UI should draw to show the user where to place the
|
||||||
* barcode. The actual captured image should be a bit larger than indicated because they might
|
* barcode. This target helps with alignment as well as forces the user to hold the device
|
||||||
* frame the shot too tightly. This target helps with alignment as well as forces the user to hold
|
* far enough away to ensure the image will be in focus.
|
||||||
* the device far enough away to ensure the image will be in focus.
|
|
||||||
*
|
*
|
||||||
* @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() {
|
||||||
if (mFramingRect == null) {
|
if (framingRect == null) {
|
||||||
int size = (mScreenResolution.x < mScreenResolution.y ? mScreenResolution.x :
|
int width = cameraResolution.x * 3 / 4;
|
||||||
mScreenResolution.y) * 3 / 4;
|
if (width < MIN_FRAME_WIDTH) {
|
||||||
int leftOffset = (mScreenResolution.x - size) / 2;
|
width = MIN_FRAME_WIDTH;
|
||||||
int topOffset = (mScreenResolution.y - size) / 2;
|
} else if (width > MAX_FRAME_WIDTH) {
|
||||||
mFramingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size);
|
width = MAX_FRAME_WIDTH;
|
||||||
Log.v(TAG, "Calculated framing rect: " + mFramingRect);
|
}
|
||||||
|
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 mFramingRect;
|
return framingRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -171,31 +216,31 @@ final class CameraManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preview frames are delivered here, which we pass on to the registered handler. Make sure to
|
* A factory method to build the appropriate LuminanceSource object based on the format
|
||||||
* clear the handler so it will only receive one message.
|
* of the preview buffers, as described by Camera.Parameters.
|
||||||
|
*
|
||||||
|
* @param data A preview frame.
|
||||||
|
* @param width The width of the image.
|
||||||
|
* @param height The height of the image.
|
||||||
|
* @return A BaseLuminanceSource subclass.
|
||||||
*/
|
*/
|
||||||
private final Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
|
public BaseLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
|
||||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
Rect rect = getFramingRect();
|
||||||
camera.setPreviewCallback(null);
|
switch (previewFormat) {
|
||||||
if (mPreviewHandler != null) {
|
case PixelFormat.YCbCr_420_SP:
|
||||||
Message message = mPreviewHandler.obtainMessage(mPreviewMessage, mScreenResolution.x,
|
case PixelFormat.YCbCr_422_SP:
|
||||||
mScreenResolution.y, data);
|
return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
|
||||||
message.sendToTarget();
|
rect.width(), rect.height());
|
||||||
mPreviewHandler = null;
|
default:
|
||||||
}
|
// There's no PixelFormat constant for this buffer format yet.
|
||||||
|
if (previewFormatString.equals("yuv422i-yuyv")) {
|
||||||
|
return new InterleavedYUV422LuminanceSource(data, width, height, rect.left, rect.top,
|
||||||
|
rect.width(), rect.height());
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
return null;
|
||||||
|
}
|
||||||
private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
|
|
||||||
public void onAutoFocus(boolean success, Camera camera) {
|
|
||||||
if (mAutoFocusHandler != null) {
|
|
||||||
Message message = mAutoFocusHandler.obtainMessage(mAutoFocusMessage, success);
|
|
||||||
// Simulate continuous autofocus by sending a focus request every 1.5 seconds.
|
|
||||||
mAutoFocusHandler.sendMessageDelayed(message, 1500L);
|
|
||||||
mAutoFocusHandler = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the camera up to take preview images which are used for both preview and decoding. We're
|
* Sets the camera up to take preview images which are used for both preview and decoding. We're
|
||||||
|
@ -203,13 +248,21 @@ final class CameraManager {
|
||||||
* specify it explicitly with setPreviewFormat().
|
* specify it explicitly with setPreviewFormat().
|
||||||
*/
|
*/
|
||||||
private void setCameraParameters() {
|
private void setCameraParameters() {
|
||||||
Camera.Parameters parameters = mCamera.getParameters();
|
Camera.Parameters parameters = camera.getParameters();
|
||||||
Camera.Size size = parameters.getPreviewSize();
|
Camera.Size size = parameters.getPreviewSize();
|
||||||
Log.v(TAG, "Default preview size: " + size.width + ", " + size.height);
|
Log.v(TAG, "Default preview size: " + size.width + ", " + size.height);
|
||||||
Log.v(TAG, "Default preview format: " + parameters.getPreviewFormat());
|
previewFormat = parameters.getPreviewFormat();
|
||||||
Log.v(TAG, "Setting preview size: " + mScreenResolution.x + ", " + mScreenResolution.y);
|
previewFormatString = parameters.get("preview-format");
|
||||||
|
Log.v(TAG, "Default preview format: " + previewFormat);
|
||||||
|
|
||||||
parameters.setPreviewSize(mScreenResolution.x, mScreenResolution.y);
|
// Ensure that the camera resolution is a multiple of 8, as the screen may not be.
|
||||||
|
// TODO: A better solution would be to request the supported preview resolutions
|
||||||
|
// and pick the best match, but this parameter is not standardized in Cupcake.
|
||||||
|
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);
|
||||||
|
|
||||||
// FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
|
// FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
|
||||||
parameters.set("flash-value", 2);
|
parameters.set("flash-value", 2);
|
||||||
|
@ -217,16 +270,16 @@ final class CameraManager {
|
||||||
// This is the standard setting to turn the flash off that all devices should honor.
|
// This is the standard setting to turn the flash off that all devices should honor.
|
||||||
parameters.set("flash-mode", "off");
|
parameters.set("flash-mode", "off");
|
||||||
|
|
||||||
mCamera.setParameters(parameters);
|
camera.setParameters(parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Point getScreenResolution() {
|
private Point getScreenResolution() {
|
||||||
if (mScreenResolution == null) {
|
if (screenResolution == null) {
|
||||||
WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
|
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||||
Display display = manager.getDefaultDisplay();
|
Display display = manager.getDefaultDisplay();
|
||||||
mScreenResolution = new Point(display.getWidth(), display.getHeight());
|
screenResolution = new Point(display.getWidth(), display.getHeight());
|
||||||
}
|
}
|
||||||
return mScreenResolution;
|
return screenResolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,12 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
package com.google.zxing.client.android;
|
||||||
|
|
||||||
|
import com.google.zxing.Result;
|
||||||
|
import com.google.zxing.ResultPoint;
|
||||||
|
import com.google.zxing.client.android.result.ResultButtonListener;
|
||||||
|
import com.google.zxing.client.android.result.ResultHandler;
|
||||||
|
import com.google.zxing.client.android.result.ResultHandlerFactory;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
@ -54,20 +60,16 @@ import android.view.WindowManager;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import com.google.zxing.Result;
|
|
||||||
import com.google.zxing.ResultPoint;
|
|
||||||
import com.google.zxing.client.android.result.ResultButtonListener;
|
|
||||||
import com.google.zxing.client.android.result.ResultHandler;
|
|
||||||
import com.google.zxing.client.android.result.ResultHandlerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The barcode reader activity itself. This is loosely based on the CameraPreview
|
* The barcode reader activity itself. This is loosely based on the CameraPreview
|
||||||
* example included in the Android SDK.
|
* example included in the Android SDK.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
*/
|
*/
|
||||||
public final class CaptureActivity extends Activity implements SurfaceHolder.Callback {
|
public final class CaptureActivity extends Activity implements SurfaceHolder.Callback {
|
||||||
|
|
||||||
private static final String TAG = "CaptureActivity";
|
private static final String TAG = "CaptureActivity";
|
||||||
|
|
||||||
private static final int SHARE_ID = Menu.FIRST;
|
private static final int SHARE_ID = Menu.FIRST;
|
||||||
|
@ -92,23 +94,31 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
NONE
|
NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
public CaptureActivityHandler mHandler;
|
public CaptureActivityHandler handler;
|
||||||
|
|
||||||
private ViewfinderView mViewfinderView;
|
private ViewfinderView viewfinderView;
|
||||||
private View mStatusView;
|
private View statusView;
|
||||||
private View mResultView;
|
private View resultView;
|
||||||
private MediaPlayer mMediaPlayer;
|
private MediaPlayer mediaPlayer;
|
||||||
private Result mLastResult;
|
private Result lastResult;
|
||||||
private boolean mHasSurface;
|
private boolean hasSurface;
|
||||||
private boolean mPlayBeep;
|
private boolean playBeep;
|
||||||
private boolean mVibrate;
|
private boolean vibrate;
|
||||||
private boolean mCopyToClipboard;
|
private boolean copyToClipboard;
|
||||||
private Source mSource;
|
private Source source;
|
||||||
private String mSourceUrl;
|
private String sourceUrl;
|
||||||
private String mDecodeMode;
|
private String decodeMode;
|
||||||
private String mVersionName;
|
private String versionName;
|
||||||
|
|
||||||
private final OnCompletionListener mBeepListener = new BeepListener();
|
private final OnCompletionListener beepListener = new BeepListener();
|
||||||
|
|
||||||
|
private final DialogInterface.OnClickListener aboutListener =
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.zxing_url)));
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
|
@ -120,12 +130,12 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
setContentView(R.layout.capture);
|
setContentView(R.layout.capture);
|
||||||
|
|
||||||
CameraManager.init(getApplication());
|
CameraManager.init(getApplication());
|
||||||
mViewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
|
viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
|
||||||
mResultView = findViewById(R.id.result_view);
|
resultView = findViewById(R.id.result_view);
|
||||||
mStatusView = findViewById(R.id.status_view);
|
statusView = findViewById(R.id.status_view);
|
||||||
mHandler = null;
|
handler = null;
|
||||||
mLastResult = null;
|
lastResult = null;
|
||||||
mHasSurface = false;
|
hasSurface = false;
|
||||||
|
|
||||||
showHelpOnFirstLaunch();
|
showHelpOnFirstLaunch();
|
||||||
}
|
}
|
||||||
|
@ -136,7 +146,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
|
|
||||||
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
|
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
|
||||||
SurfaceHolder surfaceHolder = surfaceView.getHolder();
|
SurfaceHolder surfaceHolder = surfaceView.getHolder();
|
||||||
if (mHasSurface) {
|
if (hasSurface) {
|
||||||
// The activity was paused but not stopped, so the surface still exists. Therefore
|
// The activity was paused but not stopped, so the surface still exists. Therefore
|
||||||
// surfaceCreated() won't be called, so init the camera here.
|
// surfaceCreated() won't be called, so init the camera here.
|
||||||
initCamera(surfaceHolder);
|
initCamera(surfaceHolder);
|
||||||
|
@ -150,52 +160,52 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
String action = intent == null ? null : intent.getAction();
|
String action = intent == null ? null : intent.getAction();
|
||||||
String dataString = intent == null ? null : intent.getDataString();
|
String dataString = intent == null ? null : intent.getDataString();
|
||||||
if (intent != null && action != null) {
|
if (intent != null && action != null) {
|
||||||
if (action.equals(Intents.Scan.ACTION) || action.equals(Intents.Scan.DEPRECATED_ACTION)) {
|
if (action.equals(Intents.Scan.ACTION)) {
|
||||||
// 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.
|
||||||
mSource = Source.NATIVE_APP_INTENT;
|
source = Source.NATIVE_APP_INTENT;
|
||||||
mDecodeMode = intent.getStringExtra(Intents.Scan.MODE);
|
decodeMode = intent.getStringExtra(Intents.Scan.MODE);
|
||||||
resetStatusView();
|
resetStatusView();
|
||||||
} 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.
|
||||||
mSource = Source.PRODUCT_SEARCH_LINK;
|
source = Source.PRODUCT_SEARCH_LINK;
|
||||||
mSourceUrl = dataString;
|
sourceUrl = dataString;
|
||||||
mDecodeMode = Intents.Scan.PRODUCT_MODE;
|
decodeMode = Intents.Scan.PRODUCT_MODE;
|
||||||
resetStatusView();
|
resetStatusView();
|
||||||
} else if (dataString != null && dataString.equals(ZXING_URL)) {
|
} else if (dataString != null && dataString.equals(ZXING_URL)) {
|
||||||
// Scan all formats and handle the results ourselves.
|
// Scan all formats and handle the results ourselves.
|
||||||
// TODO: In the future we could allow the hyperlink to include a URL to send the results to.
|
// TODO: In the future we could allow the hyperlink to include a URL to send the results to.
|
||||||
mSource = Source.ZXING_LINK;
|
source = Source.ZXING_LINK;
|
||||||
mSourceUrl = dataString;
|
sourceUrl = dataString;
|
||||||
mDecodeMode = null;
|
decodeMode = null;
|
||||||
resetStatusView();
|
resetStatusView();
|
||||||
} else {
|
} else {
|
||||||
// Scan all formats and handle the results ourselves (launched from Home).
|
// Scan all formats and handle the results ourselves (launched from Home).
|
||||||
mSource = Source.NONE;
|
source = Source.NONE;
|
||||||
mDecodeMode = null;
|
decodeMode = null;
|
||||||
resetStatusView();
|
resetStatusView();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mSource = Source.NONE;
|
source = Source.NONE;
|
||||||
mDecodeMode = null;
|
decodeMode = null;
|
||||||
if (mLastResult == null) {
|
if (lastResult == null) {
|
||||||
resetStatusView();
|
resetStatusView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
mPlayBeep = prefs.getBoolean(PreferencesActivity.KEY_PLAY_BEEP, true);
|
playBeep = prefs.getBoolean(PreferencesActivity.KEY_PLAY_BEEP, true);
|
||||||
mVibrate = prefs.getBoolean(PreferencesActivity.KEY_VIBRATE, false);
|
vibrate = prefs.getBoolean(PreferencesActivity.KEY_VIBRATE, false);
|
||||||
mCopyToClipboard = prefs.getBoolean(PreferencesActivity.KEY_COPY_TO_CLIPBOARD, true);
|
copyToClipboard = prefs.getBoolean(PreferencesActivity.KEY_COPY_TO_CLIPBOARD, true);
|
||||||
initBeepSound();
|
initBeepSound();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
if (mHandler != null) {
|
if (handler != null) {
|
||||||
mHandler.quitSynchronously();
|
handler.quitSynchronously();
|
||||||
mHandler = null;
|
handler = null;
|
||||||
}
|
}
|
||||||
CameraManager.get().closeDriver();
|
CameraManager.get().closeDriver();
|
||||||
}
|
}
|
||||||
|
@ -203,13 +213,13 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
@Override
|
@Override
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
if (mSource == Source.NATIVE_APP_INTENT) {
|
if (source == Source.NATIVE_APP_INTENT) {
|
||||||
setResult(RESULT_CANCELED);
|
setResult(RESULT_CANCELED);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
} else if ((mSource == Source.NONE || mSource == Source.ZXING_LINK) && mLastResult != null) {
|
} else if ((source == Source.NONE || source == Source.ZXING_LINK) && lastResult != null) {
|
||||||
resetStatusView();
|
resetStatusView();
|
||||||
mHandler.sendEmptyMessage(R.id.restart_preview);
|
handler.sendEmptyMessage(R.id.restart_preview);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (keyCode == KeyEvent.KEYCODE_FOCUS || keyCode == KeyEvent.KEYCODE_CAMERA) {
|
} else if (keyCode == KeyEvent.KEYCODE_FOCUS || keyCode == KeyEvent.KEYCODE_CAMERA) {
|
||||||
|
@ -236,7 +246,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
@Override
|
@Override
|
||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
super.onPrepareOptionsMenu(menu);
|
super.onPrepareOptionsMenu(menu);
|
||||||
menu.findItem(SHARE_ID).setVisible(mLastResult == null);
|
menu.findItem(SHARE_ID).setVisible(lastResult == null);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,10 +273,10 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
}
|
}
|
||||||
case ABOUT_ID:
|
case ABOUT_ID:
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setTitle(getString(R.string.title_about) + mVersionName);
|
builder.setTitle(getString(R.string.title_about) + versionName);
|
||||||
builder.setMessage(getString(R.string.msg_about) + "\n\n" + getString(R.string.zxing_url));
|
builder.setMessage(getString(R.string.msg_about) + "\n\n" + getString(R.string.zxing_url));
|
||||||
builder.setIcon(R.drawable.zxing_icon);
|
builder.setIcon(R.drawable.zxing_icon);
|
||||||
builder.setPositiveButton(R.string.button_open_browser, mAboutListener);
|
builder.setPositiveButton(R.string.button_open_browser, aboutListener);
|
||||||
builder.setNegativeButton(R.string.button_cancel, null);
|
builder.setNegativeButton(R.string.button_cancel, null);
|
||||||
builder.show();
|
builder.show();
|
||||||
break;
|
break;
|
||||||
|
@ -280,22 +290,15 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
super.onConfigurationChanged(config);
|
super.onConfigurationChanged(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final DialogInterface.OnClickListener mAboutListener = new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.zxing_url)));
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
if (!mHasSurface) {
|
if (!hasSurface) {
|
||||||
mHasSurface = true;
|
hasSurface = true;
|
||||||
initCamera(holder);
|
initCamera(holder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||||
mHasSurface = false;
|
hasSurface = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||||
|
@ -309,11 +312,11 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
* @param barcode A greyscale bitmap of the camera data which was decoded.
|
* @param barcode A greyscale bitmap of the camera data which was decoded.
|
||||||
*/
|
*/
|
||||||
public void handleDecode(Result rawResult, Bitmap barcode) {
|
public void handleDecode(Result rawResult, Bitmap barcode) {
|
||||||
mLastResult = rawResult;
|
lastResult = rawResult;
|
||||||
playBeepSoundAndVibrate();
|
playBeepSoundAndVibrate();
|
||||||
drawResultPoints(barcode, rawResult);
|
drawResultPoints(barcode, rawResult);
|
||||||
|
|
||||||
switch (mSource) {
|
switch (source) {
|
||||||
case NATIVE_APP_INTENT:
|
case NATIVE_APP_INTENT:
|
||||||
case PRODUCT_SEARCH_LINK:
|
case PRODUCT_SEARCH_LINK:
|
||||||
handleDecodeExternally(rawResult, barcode);
|
handleDecodeExternally(rawResult, barcode);
|
||||||
|
@ -358,9 +361,9 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
|
|
||||||
// Put up our own UI for how to handle the decoded contents.
|
// Put up our own UI for how to handle the decoded contents.
|
||||||
private void handleDecodeInternally(Result rawResult, Bitmap barcode) {
|
private void handleDecodeInternally(Result rawResult, Bitmap barcode) {
|
||||||
mStatusView.setVisibility(View.GONE);
|
statusView.setVisibility(View.GONE);
|
||||||
mViewfinderView.setVisibility(View.GONE);
|
viewfinderView.setVisibility(View.GONE);
|
||||||
mResultView.setVisibility(View.VISIBLE);
|
resultView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
ImageView barcodeImageView = (ImageView) findViewById(R.id.barcode_image_view);
|
ImageView barcodeImageView = (ImageView) findViewById(R.id.barcode_image_view);
|
||||||
barcodeImageView.setMaxWidth(MAX_RESULT_IMAGE_SIZE);
|
barcodeImageView.setMaxWidth(MAX_RESULT_IMAGE_SIZE);
|
||||||
|
@ -398,7 +401,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCopyToClipboard) {
|
if (copyToClipboard) {
|
||||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||||
clipboard.setText(displayContents);
|
clipboard.setText(displayContents);
|
||||||
}
|
}
|
||||||
|
@ -406,7 +409,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
|
|
||||||
// Briefly show the contents of the barcode, then handle the result outside Barcode Scanner.
|
// Briefly show the contents of the barcode, then handle the result outside Barcode Scanner.
|
||||||
private void handleDecodeExternally(Result rawResult, Bitmap barcode) {
|
private void handleDecodeExternally(Result rawResult, Bitmap barcode) {
|
||||||
mViewfinderView.drawResultBitmap(barcode);
|
viewfinderView.drawResultBitmap(barcode);
|
||||||
|
|
||||||
// Since this message will only be shown for a second, just tell the user what kind of
|
// Since this message will only be shown for a second, just tell the user what kind of
|
||||||
// barcode was found (e.g. contact info) rather than the full contents, which they won't
|
// barcode was found (e.g. contact info) rather than the full contents, which they won't
|
||||||
|
@ -417,30 +420,30 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
textView.setTextSize(18.0f);
|
textView.setTextSize(18.0f);
|
||||||
textView.setText(getString(resultHandler.getDisplayTitle()));
|
textView.setText(getString(resultHandler.getDisplayTitle()));
|
||||||
|
|
||||||
mStatusView.setBackgroundColor(getResources().getColor(R.color.transparent));
|
statusView.setBackgroundColor(getResources().getColor(R.color.transparent));
|
||||||
|
|
||||||
if (mCopyToClipboard) {
|
if (copyToClipboard) {
|
||||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||||
clipboard.setText(resultHandler.getDisplayContents());
|
clipboard.setText(resultHandler.getDisplayContents());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSource == Source.NATIVE_APP_INTENT) {
|
if (source == Source.NATIVE_APP_INTENT) {
|
||||||
// Hand back whatever action they requested - this can be changed to Intents.Scan.ACTION when
|
// Hand back whatever action they requested - this can be changed to Intents.Scan.ACTION when
|
||||||
// the deprecated intent is retired.
|
// the deprecated intent is retired.
|
||||||
Intent intent = new Intent(getIntent().getAction());
|
Intent intent = new Intent(getIntent().getAction());
|
||||||
intent.putExtra(Intents.Scan.RESULT, rawResult.toString());
|
intent.putExtra(Intents.Scan.RESULT, rawResult.toString());
|
||||||
intent.putExtra(Intents.Scan.RESULT_FORMAT, rawResult.getBarcodeFormat().toString());
|
intent.putExtra(Intents.Scan.RESULT_FORMAT, rawResult.getBarcodeFormat().toString());
|
||||||
Message message = Message.obtain(mHandler, R.id.return_scan_result);
|
Message message = Message.obtain(handler, R.id.return_scan_result);
|
||||||
message.obj = intent;
|
message.obj = intent;
|
||||||
mHandler.sendMessageDelayed(message, INTENT_RESULT_DURATION);
|
handler.sendMessageDelayed(message, INTENT_RESULT_DURATION);
|
||||||
} else if (mSource == Source.PRODUCT_SEARCH_LINK) {
|
} else if (source == Source.PRODUCT_SEARCH_LINK) {
|
||||||
// Reformulate the URL which triggered us into a query, so that the request goes to the same
|
// Reformulate the URL which triggered us into a query, so that the request goes to the same
|
||||||
// TLD as the scan URL.
|
// TLD as the scan URL.
|
||||||
Message message = Message.obtain(mHandler, R.id.launch_product_query);
|
Message message = Message.obtain(handler, R.id.launch_product_query);
|
||||||
int end = mSourceUrl.lastIndexOf("/scan");
|
int end = sourceUrl.lastIndexOf("/scan");
|
||||||
message.obj = mSourceUrl.substring(0, end) + "?q=" +
|
message.obj = sourceUrl.substring(0, end) + "?q=" +
|
||||||
resultHandler.getDisplayContents().toString() + "&source=zxing";
|
resultHandler.getDisplayContents().toString() + "&source=zxing";
|
||||||
mHandler.sendMessageDelayed(message, INTENT_RESULT_DURATION);
|
handler.sendMessageDelayed(message, INTENT_RESULT_DURATION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,7 +458,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
int currentVersion = info.versionCode;
|
int currentVersion = info.versionCode;
|
||||||
// Since we're paying to talk to the PackageManager anyway, it makes sense to cache the app
|
// Since we're paying to talk to the PackageManager anyway, it makes sense to cache the app
|
||||||
// version name here for display in the about box later.
|
// version name here for display in the about box later.
|
||||||
this.mVersionName = info.versionName;
|
this.versionName = info.versionName;
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
int lastVersion = prefs.getInt(PreferencesActivity.KEY_HELP_VERSION_SHOWN, 0);
|
int lastVersion = prefs.getInt(PreferencesActivity.KEY_HELP_VERSION_SHOWN, 0);
|
||||||
if (currentVersion > lastVersion) {
|
if (currentVersion > lastVersion) {
|
||||||
|
@ -474,29 +477,29 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
* latency possible.
|
* latency possible.
|
||||||
*/
|
*/
|
||||||
private void initBeepSound() {
|
private void initBeepSound() {
|
||||||
if (mPlayBeep && mMediaPlayer == null) {
|
if (playBeep && mediaPlayer == null) {
|
||||||
mMediaPlayer = new MediaPlayer();
|
mediaPlayer = new MediaPlayer();
|
||||||
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_SYSTEM);
|
mediaPlayer.setAudioStreamType(AudioManager.STREAM_SYSTEM);
|
||||||
mMediaPlayer.setOnCompletionListener(mBeepListener);
|
mediaPlayer.setOnCompletionListener(beepListener);
|
||||||
|
|
||||||
AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
|
AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
|
||||||
try {
|
try {
|
||||||
mMediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(),
|
mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(),
|
||||||
file.getLength());
|
file.getLength());
|
||||||
file.close();
|
file.close();
|
||||||
mMediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
|
mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
|
||||||
mMediaPlayer.prepare();
|
mediaPlayer.prepare();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
mMediaPlayer = null;
|
mediaPlayer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void playBeepSoundAndVibrate() {
|
private void playBeepSoundAndVibrate() {
|
||||||
if (mPlayBeep && mMediaPlayer != null) {
|
if (playBeep && mediaPlayer != null) {
|
||||||
mMediaPlayer.start();
|
mediaPlayer.start();
|
||||||
}
|
}
|
||||||
if (mVibrate) {
|
if (vibrate) {
|
||||||
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
||||||
vibrator.vibrate(VIBRATE_DURATION);
|
vibrator.vibrate(VIBRATE_DURATION);
|
||||||
}
|
}
|
||||||
|
@ -509,27 +512,27 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
Log.w(TAG, ioe);
|
Log.w(TAG, ioe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mHandler == null) {
|
if (handler == null) {
|
||||||
boolean beginScanning = mLastResult == null;
|
boolean beginScanning = lastResult == null;
|
||||||
mHandler = new CaptureActivityHandler(this, mDecodeMode, beginScanning);
|
handler = new CaptureActivityHandler(this, decodeMode, beginScanning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetStatusView() {
|
private void resetStatusView() {
|
||||||
mResultView.setVisibility(View.GONE);
|
resultView.setVisibility(View.GONE);
|
||||||
mStatusView.setVisibility(View.VISIBLE);
|
statusView.setVisibility(View.VISIBLE);
|
||||||
mStatusView.setBackgroundColor(getResources().getColor(R.color.status_view));
|
statusView.setBackgroundColor(getResources().getColor(R.color.status_view));
|
||||||
mViewfinderView.setVisibility(View.VISIBLE);
|
viewfinderView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
TextView textView = (TextView) findViewById(R.id.status_text_view);
|
TextView textView = (TextView) findViewById(R.id.status_text_view);
|
||||||
textView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
|
textView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
|
||||||
textView.setTextSize(14.0f);
|
textView.setTextSize(14.0f);
|
||||||
textView.setText(R.string.msg_default_status);
|
textView.setText(R.string.msg_default_status);
|
||||||
mLastResult = null;
|
lastResult = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawViewfinder() {
|
public void drawViewfinder() {
|
||||||
mViewfinderView.drawViewfinder();
|
viewfinderView.drawViewfinder();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -540,5 +543,4 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
||||||
mediaPlayer.seekTo(0);
|
mediaPlayer.seekTo(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
package com.google.zxing.client.android;
|
||||||
|
|
||||||
|
import com.google.zxing.Result;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
@ -23,16 +25,16 @@ import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import com.google.zxing.Result;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class handles all the messaging which comprises the state machine for capture.
|
* This class handles all the messaging which comprises the state machine for capture.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
*/
|
*/
|
||||||
public final class CaptureActivityHandler extends Handler {
|
public final class CaptureActivityHandler extends Handler {
|
||||||
|
private final CaptureActivity activity;
|
||||||
private final CaptureActivity mActivity;
|
private final DecodeThread decodeThread;
|
||||||
private final DecodeThread mDecodeThread;
|
private State state;
|
||||||
private State mState;
|
|
||||||
|
|
||||||
private enum State {
|
private enum State {
|
||||||
PREVIEW,
|
PREVIEW,
|
||||||
|
@ -42,10 +44,10 @@ public final class CaptureActivityHandler extends Handler {
|
||||||
|
|
||||||
CaptureActivityHandler(CaptureActivity activity, String decodeMode,
|
CaptureActivityHandler(CaptureActivity activity, String decodeMode,
|
||||||
boolean beginScanning) {
|
boolean beginScanning) {
|
||||||
mActivity = activity;
|
this.activity = activity;
|
||||||
mDecodeThread = new DecodeThread(activity, decodeMode);
|
decodeThread = new DecodeThread(activity, decodeMode);
|
||||||
mDecodeThread.start();
|
decodeThread.start();
|
||||||
mState = State.SUCCESS;
|
state = State.SUCCESS;
|
||||||
|
|
||||||
// Start ourselves capturing previews and decoding.
|
// Start ourselves capturing previews and decoding.
|
||||||
CameraManager.get().startPreview();
|
CameraManager.get().startPreview();
|
||||||
|
@ -60,7 +62,7 @@ public final class CaptureActivityHandler extends Handler {
|
||||||
case R.id.auto_focus:
|
case R.id.auto_focus:
|
||||||
// When one auto focus pass finishes, start another. This is the closest thing to
|
// When one auto focus pass finishes, start another. This is the closest thing to
|
||||||
// continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
|
// continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
|
||||||
if (mState == State.PREVIEW) {
|
if (state == State.PREVIEW) {
|
||||||
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
|
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -68,34 +70,34 @@ public final class CaptureActivityHandler extends Handler {
|
||||||
restartPreviewAndDecode();
|
restartPreviewAndDecode();
|
||||||
break;
|
break;
|
||||||
case R.id.decode_succeeded:
|
case R.id.decode_succeeded:
|
||||||
mState = State.SUCCESS;
|
state = State.SUCCESS;
|
||||||
Bundle bundle = message.getData();
|
Bundle bundle = message.getData();
|
||||||
Bitmap barcode = bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
|
Bitmap barcode = bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
|
||||||
mActivity.handleDecode((Result) message.obj, barcode);
|
activity.handleDecode((Result) message.obj, barcode);
|
||||||
break;
|
break;
|
||||||
case R.id.decode_failed:
|
case R.id.decode_failed:
|
||||||
// We're decoding as fast as possible, so when one decode fails, start another.
|
// We're decoding as fast as possible, so when one decode fails, start another.
|
||||||
mState = State.PREVIEW;
|
state = State.PREVIEW;
|
||||||
CameraManager.get().requestPreviewFrame(mDecodeThread.mHandler, R.id.decode);
|
CameraManager.get().requestPreviewFrame(decodeThread.handler, R.id.decode);
|
||||||
break;
|
break;
|
||||||
case R.id.return_scan_result:
|
case R.id.return_scan_result:
|
||||||
mActivity.setResult(Activity.RESULT_OK, (Intent) message.obj);
|
activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
|
||||||
mActivity.finish();
|
activity.finish();
|
||||||
break;
|
break;
|
||||||
case R.id.launch_product_query:
|
case R.id.launch_product_query:
|
||||||
String url = (String) message.obj;
|
String url = (String) message.obj;
|
||||||
mActivity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
|
activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void quitSynchronously() {
|
public void quitSynchronously() {
|
||||||
mState = State.DONE;
|
state = State.DONE;
|
||||||
CameraManager.get().stopPreview();
|
CameraManager.get().stopPreview();
|
||||||
Message quit = Message.obtain(mDecodeThread.mHandler, R.id.quit);
|
Message quit = Message.obtain(decodeThread.handler, R.id.quit);
|
||||||
quit.sendToTarget();
|
quit.sendToTarget();
|
||||||
try {
|
try {
|
||||||
mDecodeThread.join();
|
decodeThread.join();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,12 +107,11 @@ public final class CaptureActivityHandler extends Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restartPreviewAndDecode() {
|
private void restartPreviewAndDecode() {
|
||||||
if (mState == State.SUCCESS) {
|
if (state == State.SUCCESS) {
|
||||||
mState = State.PREVIEW;
|
state = State.PREVIEW;
|
||||||
CameraManager.get().requestPreviewFrame(mDecodeThread.mHandler, R.id.decode);
|
CameraManager.get().requestPreviewFrame(decodeThread.handler, R.id.decode);
|
||||||
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
|
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
|
||||||
mActivity.drawViewfinder();
|
activity.drawViewfinder();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,13 @@ package com.google.zxing.client.android;
|
||||||
|
|
||||||
import android.provider.Contacts;
|
import android.provider.Contacts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of constants to use when sending Barcode Scanner an Intent which requests a barcode
|
||||||
|
* to be encoded.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public final class Contents {
|
public final class Contents {
|
||||||
|
|
||||||
private Contents() {
|
private Contents() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,24 +94,19 @@ public final class Contents {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are new constants in Contacts.Intents.Insert for Android 1.1.
|
|
||||||
// TODO: Remove these constants once we can build against the 1.1 SDK.
|
|
||||||
private static final String SECONDARY_PHONE = "secondary_phone";
|
|
||||||
private static final String TERTIARY_PHONE = "tertiary_phone";
|
|
||||||
private static final String SECONDARY_EMAIL = "secondary_email";
|
|
||||||
private static final String TERTIARY_EMAIL = "tertiary_email";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When using Type.CONTACT, these arrays provide the keys for adding or retrieving multiple
|
* When using Type.CONTACT, these arrays provide the keys for adding or retrieving multiple
|
||||||
* phone numbers and addresses.
|
* phone numbers and addresses.
|
||||||
*/
|
*/
|
||||||
public static final String[] PHONE_KEYS = {
|
public static final String[] PHONE_KEYS = {
|
||||||
Contacts.Intents.Insert.PHONE, SECONDARY_PHONE, TERTIARY_PHONE
|
Contacts.Intents.Insert.PHONE,
|
||||||
|
Contacts.Intents.Insert.SECONDARY_PHONE,
|
||||||
|
Contacts.Intents.Insert.TERTIARY_PHONE
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final String[] EMAIL_KEYS = {
|
public static final String[] EMAIL_KEYS = {
|
||||||
Contacts.Intents.Insert.EMAIL, SECONDARY_EMAIL, TERTIARY_EMAIL
|
Contacts.Intents.Insert.EMAIL,
|
||||||
|
Contacts.Intents.Insert.SECONDARY_EMAIL,
|
||||||
|
Contacts.Intents.Insert.TERTIARY_EMAIL
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import com.google.zxing.Result;
|
||||||
import com.google.zxing.common.GlobalHistogramBinarizer;
|
import com.google.zxing.common.GlobalHistogramBinarizer;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
@ -38,19 +37,20 @@ import java.util.Vector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This thread does all the heavy lifting of decoding the images.
|
* This thread does all the heavy lifting of decoding the images.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
*/
|
*/
|
||||||
final class DecodeThread extends Thread {
|
final class DecodeThread extends Thread {
|
||||||
|
|
||||||
public static final String BARCODE_BITMAP = "barcode_bitmap";
|
public static final String BARCODE_BITMAP = "barcode_bitmap";
|
||||||
private static final String TAG = "DecodeThread";
|
private static final String TAG = "DecodeThread";
|
||||||
|
|
||||||
public Handler mHandler;
|
public Handler handler;
|
||||||
private final CaptureActivity mActivity;
|
private final CaptureActivity activity;
|
||||||
private final MultiFormatReader mMultiFormatReader;
|
private final MultiFormatReader multiFormatReader;
|
||||||
|
|
||||||
DecodeThread(CaptureActivity activity, String mode) {
|
DecodeThread(CaptureActivity activity, String mode) {
|
||||||
mActivity = activity;
|
this.activity = activity;
|
||||||
mMultiFormatReader = new MultiFormatReader();
|
multiFormatReader = new MultiFormatReader();
|
||||||
|
|
||||||
// The prefs can't change while the thread is running, so pick them up once here.
|
// The prefs can't change while the thread is running, so pick them up once here.
|
||||||
if (mode == null || mode.length() == 0) {
|
if (mode == null || mode.length() == 0) {
|
||||||
|
@ -80,7 +80,7 @@ final class DecodeThread extends Thread {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Looper.prepare();
|
Looper.prepare();
|
||||||
mHandler = new Handler() {
|
handler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message message) {
|
public void handleMessage(Message message) {
|
||||||
switch (message.what) {
|
switch (message.what) {
|
||||||
|
@ -104,7 +104,7 @@ final class DecodeThread extends Thread {
|
||||||
vector.addElement(BarcodeFormat.EAN_13);
|
vector.addElement(BarcodeFormat.EAN_13);
|
||||||
vector.addElement(BarcodeFormat.EAN_8);
|
vector.addElement(BarcodeFormat.EAN_8);
|
||||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
||||||
mMultiFormatReader.setHints(hints);
|
multiFormatReader.setHints(hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -121,7 +121,7 @@ final class DecodeThread extends Thread {
|
||||||
vector.addElement(BarcodeFormat.CODE_128);
|
vector.addElement(BarcodeFormat.CODE_128);
|
||||||
vector.addElement(BarcodeFormat.ITF);
|
vector.addElement(BarcodeFormat.ITF);
|
||||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
||||||
mMultiFormatReader.setHints(hints);
|
multiFormatReader.setHints(hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDecodeQRMode() {
|
private void setDecodeQRMode() {
|
||||||
|
@ -129,7 +129,7 @@ final class DecodeThread extends Thread {
|
||||||
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>(1);
|
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>(1);
|
||||||
vector.addElement(BarcodeFormat.QR_CODE);
|
vector.addElement(BarcodeFormat.QR_CODE);
|
||||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
||||||
mMultiFormatReader.setHints(hints);
|
multiFormatReader.setHints(hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,7 +148,7 @@ final class DecodeThread extends Thread {
|
||||||
vector.addElement(BarcodeFormat.ITF);
|
vector.addElement(BarcodeFormat.ITF);
|
||||||
vector.addElement(BarcodeFormat.QR_CODE);
|
vector.addElement(BarcodeFormat.QR_CODE);
|
||||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
||||||
mMultiFormatReader.setHints(hints);
|
multiFormatReader.setHints(hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,12 +163,10 @@ final class DecodeThread extends Thread {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
boolean success;
|
boolean success;
|
||||||
Result rawResult = null;
|
Result rawResult = null;
|
||||||
Rect rect = CameraManager.get().getFramingRect();
|
BaseLuminanceSource source = CameraManager.get().buildLuminanceSource(data, width, height);
|
||||||
YUVLuminanceSource source = new YUVLuminanceSource(data, width, height, rect.left, rect.top,
|
|
||||||
rect.width(), rect.height());
|
|
||||||
BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
|
BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
|
||||||
try {
|
try {
|
||||||
rawResult = mMultiFormatReader.decodeWithState(bitmap);
|
rawResult = multiFormatReader.decodeWithState(bitmap);
|
||||||
success = true;
|
success = true;
|
||||||
} catch (ReaderException e) {
|
} catch (ReaderException e) {
|
||||||
success = false;
|
success = false;
|
||||||
|
@ -177,15 +175,14 @@ final class DecodeThread extends Thread {
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
Log.v(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
|
Log.v(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
|
||||||
Message message = Message.obtain(mActivity.mHandler, R.id.decode_succeeded, rawResult);
|
Message message = Message.obtain(activity.handler, R.id.decode_succeeded, rawResult);
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putParcelable(BARCODE_BITMAP, source.renderToBitmap());
|
bundle.putParcelable(BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
|
||||||
message.setData(bundle);
|
message.setData(bundle);
|
||||||
message.sendToTarget();
|
message.sendToTarget();
|
||||||
} else {
|
} else {
|
||||||
Message message = Message.obtain(mActivity.mHandler, R.id.decode_failed);
|
Message message = Message.obtain(activity.handler, R.id.decode_failed);
|
||||||
message.sendToTarget();
|
message.sendToTarget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,20 +35,82 @@ import android.widget.TextView;
|
||||||
/**
|
/**
|
||||||
* This class encodes data from an Intent into a QR code, and then displays it full screen so that
|
* This class encodes data from an Intent into a QR code, and then displays it full screen so that
|
||||||
* another person can scan it with their device.
|
* another person can scan it with their device.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
*/
|
*/
|
||||||
public final class EncodeActivity extends Activity {
|
public final class EncodeActivity extends Activity {
|
||||||
|
private QRCodeEncoder qrCodeEncoder;
|
||||||
|
private ProgressDialog progressDialog;
|
||||||
|
private boolean firstLayout;
|
||||||
|
|
||||||
private QRCodeEncoder mQRCodeEncoder;
|
/**
|
||||||
private ProgressDialog mProgressDialog;
|
* This needs to be delayed until after the first layout so that the view dimensions will be
|
||||||
private boolean mFirstLayout;
|
* available.
|
||||||
|
*/
|
||||||
|
public final OnGlobalLayoutListener layoutListener = new OnGlobalLayoutListener() {
|
||||||
|
public void onGlobalLayout() {
|
||||||
|
if (firstLayout) {
|
||||||
|
View layout = findViewById(R.id.encode_view);
|
||||||
|
int width = layout.getWidth();
|
||||||
|
int height = layout.getHeight();
|
||||||
|
int smallerDimension = width < height ? width : height;
|
||||||
|
smallerDimension = smallerDimension * 7 / 8;
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
try {
|
||||||
|
qrCodeEncoder = new QRCodeEncoder(EncodeActivity.this, intent);
|
||||||
|
setTitle(getString(R.string.app_name) + " - " + qrCodeEncoder.getTitle());
|
||||||
|
qrCodeEncoder.requestBarcode(handler, smallerDimension);
|
||||||
|
progressDialog = ProgressDialog.show(EncodeActivity.this, null,
|
||||||
|
getString(R.string.msg_encode_in_progress), true, true, cancelListener);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
showErrorMessage(R.string.msg_encode_contents_failed);
|
||||||
|
}
|
||||||
|
firstLayout = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public final Handler handler = new Handler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
switch (message.what) {
|
||||||
|
case R.id.encode_succeeded:
|
||||||
|
progressDialog.dismiss();
|
||||||
|
progressDialog = null;
|
||||||
|
Bitmap image = (Bitmap) message.obj;
|
||||||
|
ImageView view = (ImageView) findViewById(R.id.image_view);
|
||||||
|
view.setImageBitmap(image);
|
||||||
|
TextView contents = (TextView) findViewById(R.id.contents_text_view);
|
||||||
|
contents.setText(qrCodeEncoder.getDisplayContents());
|
||||||
|
qrCodeEncoder = null;
|
||||||
|
break;
|
||||||
|
case R.id.encode_failed:
|
||||||
|
showErrorMessage(R.string.msg_encode_barcode_failed);
|
||||||
|
qrCodeEncoder = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final OnClickListener clickListener = new OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final OnCancelListener cancelListener = new OnCancelListener() {
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
if (intent != null && (intent.getAction().equals(Intents.Encode.ACTION) ||
|
if (intent != null && (intent.getAction().equals(Intents.Encode.ACTION))) {
|
||||||
intent.getAction().equals(Intents.Encode.DEPRECATED_ACTION))) {
|
|
||||||
setContentView(R.layout.encode);
|
setContentView(R.layout.encode);
|
||||||
} else {
|
} else {
|
||||||
finish();
|
finish();
|
||||||
|
@ -60,81 +122,18 @@ public final class EncodeActivity extends Activity {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
View layout = findViewById(R.id.encode_view);
|
View layout = findViewById(R.id.encode_view);
|
||||||
layout.getViewTreeObserver().addOnGlobalLayoutListener(mLayoutListener);
|
layout.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
|
||||||
mFirstLayout = true;
|
firstLayout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This needs to be delayed until after the first layout so that the view dimensions will be
|
|
||||||
* available.
|
|
||||||
*/
|
|
||||||
public final OnGlobalLayoutListener mLayoutListener = new OnGlobalLayoutListener() {
|
|
||||||
public void onGlobalLayout() {
|
|
||||||
if (mFirstLayout) {
|
|
||||||
View layout = findViewById(R.id.encode_view);
|
|
||||||
int width = layout.getWidth();
|
|
||||||
int height = layout.getHeight();
|
|
||||||
int smallerDimension = width < height ? width : height;
|
|
||||||
smallerDimension = smallerDimension * 7 / 8;
|
|
||||||
|
|
||||||
Intent intent = getIntent();
|
|
||||||
try {
|
|
||||||
mQRCodeEncoder = new QRCodeEncoder(EncodeActivity.this, intent);
|
|
||||||
setTitle(getString(R.string.app_name) + " - " + mQRCodeEncoder.getTitle());
|
|
||||||
mQRCodeEncoder.requestBarcode(mHandler, smallerDimension);
|
|
||||||
mProgressDialog = ProgressDialog.show(EncodeActivity.this, null,
|
|
||||||
getString(R.string.msg_encode_in_progress), true, true, mCancelListener);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
showErrorMessage(R.string.msg_encode_contents_failed);
|
|
||||||
}
|
|
||||||
mFirstLayout = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public final Handler mHandler = new Handler() {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
switch (message.what) {
|
|
||||||
case R.id.encode_succeeded:
|
|
||||||
mProgressDialog.dismiss();
|
|
||||||
mProgressDialog = null;
|
|
||||||
Bitmap image = (Bitmap) message.obj;
|
|
||||||
ImageView view = (ImageView) findViewById(R.id.image_view);
|
|
||||||
view.setImageBitmap(image);
|
|
||||||
TextView contents = (TextView) findViewById(R.id.contents_text_view);
|
|
||||||
contents.setText(mQRCodeEncoder.getDisplayContents());
|
|
||||||
mQRCodeEncoder = null;
|
|
||||||
break;
|
|
||||||
case R.id.encode_failed:
|
|
||||||
showErrorMessage(R.string.msg_encode_barcode_failed);
|
|
||||||
mQRCodeEncoder = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private void showErrorMessage(int message) {
|
private void showErrorMessage(int message) {
|
||||||
if (mProgressDialog != null) {
|
if (progressDialog != null) {
|
||||||
mProgressDialog.dismiss();
|
progressDialog.dismiss();
|
||||||
mProgressDialog = null;
|
progressDialog = null;
|
||||||
}
|
}
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setMessage(message);
|
builder.setMessage(message);
|
||||||
builder.setPositiveButton(R.string.button_ok, mClickListener);
|
builder.setPositiveButton(R.string.button_ok, clickListener);
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final OnClickListener mClickListener = new OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final OnCancelListener mCancelListener = new OnCancelListener() {
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,33 +25,46 @@ import android.webkit.WebViewClient;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* An HTML-based help screen with Back and Done buttons at the bottom.
|
||||||
|
*
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
*/
|
*/
|
||||||
public final class HelpActivity extends Activity {
|
public final class HelpActivity extends Activity {
|
||||||
|
|
||||||
private static final String DEFAULT_URL = "file:///android_asset/html/index.html";
|
private static final String DEFAULT_URL = "file:///android_asset/html/index.html";
|
||||||
|
|
||||||
private WebView mWebView;
|
private WebView webView;
|
||||||
private Button mBackButton;
|
private Button backButton;
|
||||||
|
|
||||||
|
private final Button.OnClickListener backListener = new Button.OnClickListener() {
|
||||||
|
public void onClick(View view) {
|
||||||
|
webView.goBack();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final Button.OnClickListener doneListener = new Button.OnClickListener() {
|
||||||
|
public void onClick(View view) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle icicle) {
|
protected void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
setContentView(R.layout.help);
|
setContentView(R.layout.help);
|
||||||
|
|
||||||
mWebView = (WebView)findViewById(R.id.help_contents);
|
webView = (WebView)findViewById(R.id.help_contents);
|
||||||
mWebView.setWebViewClient(new HelpClient());
|
webView.setWebViewClient(new HelpClient());
|
||||||
if (icicle != null) {
|
if (icicle != null) {
|
||||||
mWebView.restoreState(icicle);
|
webView.restoreState(icicle);
|
||||||
} else {
|
} else {
|
||||||
mWebView.loadUrl(DEFAULT_URL);
|
webView.loadUrl(DEFAULT_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
mBackButton = (Button)findViewById(R.id.back_button);
|
backButton = (Button)findViewById(R.id.back_button);
|
||||||
mBackButton.setOnClickListener(mBackListener);
|
backButton.setOnClickListener(backListener);
|
||||||
|
|
||||||
Button doneButton = (Button)findViewById(R.id.done_button);
|
Button doneButton = (Button)findViewById(R.id.done_button);
|
||||||
doneButton.setOnClickListener(mDoneListener);
|
doneButton.setOnClickListener(doneListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -61,40 +74,26 @@ public final class HelpActivity extends Activity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(Bundle state) {
|
protected void onSaveInstanceState(Bundle state) {
|
||||||
mWebView.saveState(state);
|
webView.saveState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
if (mWebView.canGoBack()) {
|
if (webView.canGoBack()) {
|
||||||
mWebView.goBack();
|
webView.goBack();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.onKeyDown(keyCode, event);
|
return super.onKeyDown(keyCode, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Button.OnClickListener mBackListener = new Button.OnClickListener() {
|
|
||||||
public void onClick(View view) {
|
|
||||||
mWebView.goBack();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final Button.OnClickListener mDoneListener = new Button.OnClickListener() {
|
|
||||||
public void onClick(View view) {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final class HelpClient extends WebViewClient {
|
private final class HelpClient extends WebViewClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPageFinished(WebView view, String url) {
|
public void onPageFinished(WebView view, String url) {
|
||||||
setTitle(view.getTitle());
|
setTitle(view.getTitle());
|
||||||
mBackButton.setEnabled(view.canGoBack());
|
backButton.setEnabled(view.canGoBack());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,13 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
package com.google.zxing.client.android;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides the constants to use when sending an Intent to Barcode Scanner.
|
||||||
|
* These strings are effectively API and cannot be changed.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public final class Intents {
|
public final class Intents {
|
||||||
|
|
||||||
private Intents() {
|
private Intents() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,9 +33,6 @@ public final class Intents {
|
||||||
*/
|
*/
|
||||||
public static final String ACTION = "com.google.zxing.client.android.SCAN";
|
public static final String ACTION = "com.google.zxing.client.android.SCAN";
|
||||||
|
|
||||||
// For compatibility only - do not use in new code, this will go away!
|
|
||||||
public static final String DEPRECATED_ACTION = "com.android.barcodes.SCAN";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
@ -79,9 +81,6 @@ public final class Intents {
|
||||||
*/
|
*/
|
||||||
public static final String ACTION = "com.google.zxing.client.android.ENCODE";
|
public static final String ACTION = "com.google.zxing.client.android.ENCODE";
|
||||||
|
|
||||||
// For compatibility only - do not use in new code, this will go away!
|
|
||||||
public static final String DEPRECATED_ACTION = "com.android.barcodes.ENCODE";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to encode. Use Intent.putExtra(DATA, data) where data is either a String or a
|
* The data to encode. Use Intent.putExtra(DATA, data) where data is either a String or a
|
||||||
* Bundle, depending on the type and format specified. Non-QR Code formats should
|
* Bundle, depending on the type and format specified. Non-QR Code formats should
|
||||||
|
@ -112,9 +111,6 @@ public final class Intents {
|
||||||
*/
|
*/
|
||||||
public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS";
|
public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS";
|
||||||
|
|
||||||
// For compatibility only - do not use in new code, this will go away!
|
|
||||||
public static final String DEPRECATED_ACTION = "com.android.barcodes.SEARCH_BOOK_CONTENTS";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The book to search, identified by ISBN number.
|
* The book to search, identified by ISBN number.
|
||||||
*/
|
*/
|
||||||
|
@ -139,5 +135,4 @@ public final class Intents {
|
||||||
private Share() {
|
private Share() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2009 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.android;
|
||||||
|
|
||||||
|
import com.google.zxing.LuminanceSource;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object extends LuminanceSource around an array of YUV data returned from the camera driver,
|
||||||
|
* with the option to crop to a rectangle within the full data. This can be used to exclude
|
||||||
|
* superfluous pixels around the perimeter and speed up decoding.
|
||||||
|
*
|
||||||
|
* It handles YUV 422 interleaved data, where each pixel consists of first a Y value, then
|
||||||
|
* a color value, with U and V alternating at each pixel.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
public final class InterleavedYUV422LuminanceSource extends BaseLuminanceSource {
|
||||||
|
private final byte[] yuvData;
|
||||||
|
private final int dataWidth;
|
||||||
|
private final int dataHeight;
|
||||||
|
private final int left;
|
||||||
|
private final int top;
|
||||||
|
|
||||||
|
public InterleavedYUV422LuminanceSource(byte[] yuvData, int dataWidth, int dataHeight,
|
||||||
|
int left, int top, int width, int height) {
|
||||||
|
super(width, height);
|
||||||
|
|
||||||
|
if (left + width > dataWidth || top + height > dataHeight) {
|
||||||
|
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.yuvData = yuvData;
|
||||||
|
this.dataWidth = dataWidth;
|
||||||
|
this.dataHeight = dataHeight;
|
||||||
|
this.left = left;
|
||||||
|
this.top = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getRow(int y, byte[] row) {
|
||||||
|
if (y < 0 || y >= getHeight()) {
|
||||||
|
throw new IllegalArgumentException("Requested row is outside the image: " + y);
|
||||||
|
}
|
||||||
|
int width = getWidth();
|
||||||
|
if (row == null || row.length < width) {
|
||||||
|
row = new byte[width];
|
||||||
|
}
|
||||||
|
int offset = (y + top) * dataWidth * 2 + (left * 2);
|
||||||
|
byte[] yuv = yuvData;
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
row[x] = yuv[offset + (x << 1)];
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getMatrix() {
|
||||||
|
int width = getWidth();
|
||||||
|
int height = getHeight();
|
||||||
|
int area = width * height;
|
||||||
|
byte[] matrix = new byte[area];
|
||||||
|
int inputOffset = top * dataWidth * 2 + (left * 2);
|
||||||
|
byte[] yuv = yuvData;
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
int outputOffset = y * width;
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
matrix[outputOffset + x] = yuv[inputOffset + (x << 1)];
|
||||||
|
}
|
||||||
|
inputOffset += (dataWidth * 2);
|
||||||
|
}
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCropSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LuminanceSource crop(int left, int top, int width, int height) {
|
||||||
|
return new InterleavedYUV422LuminanceSource(yuvData, dataWidth, dataHeight, left, top,
|
||||||
|
width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDataWidth() {
|
||||||
|
return dataWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDataHeight() {
|
||||||
|
return dataHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bitmap renderCroppedGreyscaleBitmap() {
|
||||||
|
int width = getWidth();
|
||||||
|
int height = getHeight();
|
||||||
|
int[] pixels = new int[width * height];
|
||||||
|
byte[] yuv = yuvData;
|
||||||
|
int inputOffset = top * dataWidth * 2 + (left * 2);
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
int outputOffset = y * width;
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
int grey = yuv[inputOffset + (x << 1)] & 0xff;
|
||||||
|
pixels[outputOffset + x] = (0xff000000) | (grey * 0x00010101);
|
||||||
|
}
|
||||||
|
inputOffset += (dataWidth * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
|
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bitmap renderFullColorBitmap(boolean halfSize) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,9 +22,10 @@ import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles any locale-specific logic for the client.
|
* Handles any locale-specific logic for the client.
|
||||||
|
*
|
||||||
|
* @author Sean Owen
|
||||||
*/
|
*/
|
||||||
public final class LocaleManager {
|
public final class LocaleManager {
|
||||||
|
|
||||||
private static final String DEFAULT_TLD = "com";
|
private static final String DEFAULT_TLD = "com";
|
||||||
private static final Map<Locale,String> GOOGLE_COUNTRY_TLD;
|
private static final Map<Locale,String> GOOGLE_COUNTRY_TLD;
|
||||||
static {
|
static {
|
||||||
|
@ -93,5 +94,4 @@ public final class LocaleManager {
|
||||||
}
|
}
|
||||||
return tld;
|
return tld;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2009 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.android;
|
||||||
|
|
||||||
|
import com.google.zxing.LuminanceSource;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object extends LuminanceSource around an array of YUV data returned from the camera driver,
|
||||||
|
* with the option to crop to a rectangle within the full data. This can be used to exclude
|
||||||
|
* superfluous pixels around the perimeter and speed up decoding.
|
||||||
|
*
|
||||||
|
* It works for any pixel format where the Y channel is planar and appears first, including
|
||||||
|
* YCbCr_420_SP and YCbCr_422_SP. Any subsequent color data will be ignored.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
public final class PlanarYUVLuminanceSource extends BaseLuminanceSource {
|
||||||
|
private final byte[] yuvData;
|
||||||
|
private final int dataWidth;
|
||||||
|
private final int dataHeight;
|
||||||
|
private final int left;
|
||||||
|
private final int top;
|
||||||
|
|
||||||
|
public PlanarYUVLuminanceSource(byte[] yuvData, int dataWidth, int dataHeight, int left, int top,
|
||||||
|
int width, int height) {
|
||||||
|
super(width, height);
|
||||||
|
|
||||||
|
if (left + width > dataWidth || top + height > dataHeight) {
|
||||||
|
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.yuvData = yuvData;
|
||||||
|
this.dataWidth = dataWidth;
|
||||||
|
this.dataHeight = dataHeight;
|
||||||
|
this.left = left;
|
||||||
|
this.top = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getRow(int y, byte[] row) {
|
||||||
|
if (y < 0 || y >= getHeight()) {
|
||||||
|
throw new IllegalArgumentException("Requested row is outside the image: " + y);
|
||||||
|
}
|
||||||
|
int width = getWidth();
|
||||||
|
if (row == null || row.length < width) {
|
||||||
|
row = new byte[width];
|
||||||
|
}
|
||||||
|
int offset = (y + top) * dataWidth + left;
|
||||||
|
System.arraycopy(yuvData, offset, row, 0, width);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getMatrix() {
|
||||||
|
int width = getWidth();
|
||||||
|
int height = getHeight();
|
||||||
|
|
||||||
|
// If the caller asks for the entire underlying image, save the copy and give them the
|
||||||
|
// original data. The docs specifically warn that result.length must be ignored.
|
||||||
|
if (width == dataWidth && height == dataHeight) {
|
||||||
|
return yuvData;
|
||||||
|
}
|
||||||
|
|
||||||
|
int area = width * height;
|
||||||
|
byte[] matrix = new byte[area];
|
||||||
|
int inputOffset = top * dataWidth + left;
|
||||||
|
|
||||||
|
// If the width matches the full width of the underlying data, perform a single copy.
|
||||||
|
if (width == dataWidth) {
|
||||||
|
System.arraycopy(yuvData, inputOffset, matrix, 0, area);
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise copy one cropped row at a time.
|
||||||
|
byte[] yuv = yuvData;
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
int outputOffset = y * width;
|
||||||
|
System.arraycopy(yuv, inputOffset, matrix, outputOffset, width);
|
||||||
|
inputOffset += dataWidth;
|
||||||
|
}
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCropSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LuminanceSource crop(int left, int top, int width, int height) {
|
||||||
|
return new PlanarYUVLuminanceSource(yuvData, dataWidth, dataHeight, left, top, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDataWidth() {
|
||||||
|
return dataWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDataHeight() {
|
||||||
|
return dataHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bitmap renderCroppedGreyscaleBitmap() {
|
||||||
|
int width = getWidth();
|
||||||
|
int height = getHeight();
|
||||||
|
int[] pixels = new int[width * height];
|
||||||
|
byte[] yuv = yuvData;
|
||||||
|
int inputOffset = top * dataWidth + left;
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
int outputOffset = y * width;
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
int grey = yuv[inputOffset + x] & 0xff;
|
||||||
|
pixels[outputOffset + x] = (0xff000000) | (grey * 0x00010101);
|
||||||
|
}
|
||||||
|
inputOffset += dataWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
|
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't be implemented here, as the color representations vary.
|
||||||
|
@Override
|
||||||
|
public Bitmap renderFullColorBitmap(boolean halfSize) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,11 @@ import android.preference.CheckBoxPreference;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main settings activity.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public final class PreferencesActivity extends PreferenceActivity
|
public final class PreferencesActivity extends PreferenceActivity
|
||||||
implements OnSharedPreferenceChangeListener {
|
implements OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
|
@ -36,8 +41,8 @@ public final class PreferencesActivity extends PreferenceActivity
|
||||||
|
|
||||||
static final String KEY_HELP_VERSION_SHOWN = "preferences_help_version_shown";
|
static final String KEY_HELP_VERSION_SHOWN = "preferences_help_version_shown";
|
||||||
|
|
||||||
CheckBoxPreference mDecode1D;
|
CheckBoxPreference decode1D;
|
||||||
CheckBoxPreference mDecodeQR;
|
CheckBoxPreference decodeQR;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle icicle) {
|
protected void onCreate(Bundle icicle) {
|
||||||
|
@ -46,19 +51,18 @@ public final class PreferencesActivity extends PreferenceActivity
|
||||||
|
|
||||||
PreferenceScreen preferences = getPreferenceScreen();
|
PreferenceScreen preferences = getPreferenceScreen();
|
||||||
preferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
|
preferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
|
||||||
mDecode1D = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_1D);
|
decode1D = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_1D);
|
||||||
mDecodeQR = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_QR);
|
decodeQR = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_QR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent the user from turning off both decode options
|
// Prevent the user from turning off both decode options
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
if (key.equals(KEY_DECODE_1D)) {
|
if (key.equals(KEY_DECODE_1D)) {
|
||||||
mDecodeQR.setEnabled(mDecode1D.isChecked());
|
decodeQR.setEnabled(decode1D.isChecked());
|
||||||
mDecodeQR.setChecked(true);
|
decodeQR.setChecked(true);
|
||||||
} else if (key.equals(KEY_DECODE_QR)) {
|
} else if (key.equals(KEY_DECODE_QR)) {
|
||||||
mDecode1D.setEnabled(mDecodeQR.isChecked());
|
decode1D.setEnabled(decodeQR.isChecked());
|
||||||
mDecode1D.setChecked(true);
|
decode1D.setChecked(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,11 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
package com.google.zxing.client.android;
|
||||||
|
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.MultiFormatWriter;
|
||||||
|
import com.google.zxing.WriterException;
|
||||||
|
import com.google.zxing.common.ByteMatrix;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
@ -23,48 +28,49 @@ import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.provider.Contacts;
|
import android.provider.Contacts;
|
||||||
import android.util.Log;
|
|
||||||
import android.telephony.PhoneNumberUtils;
|
import android.telephony.PhoneNumberUtils;
|
||||||
import com.google.zxing.BarcodeFormat;
|
import android.util.Log;
|
||||||
import com.google.zxing.MultiFormatWriter;
|
|
||||||
import com.google.zxing.WriterException;
|
|
||||||
import com.google.zxing.common.ByteMatrix;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class does the work of decoding the user's request and extracting all the data
|
||||||
|
* to be encoded in a QR Code.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public final class QRCodeEncoder {
|
public final class QRCodeEncoder {
|
||||||
|
private final Activity activity;
|
||||||
private final Activity mActivity;
|
private String contents;
|
||||||
private String mContents;
|
private String displayContents;
|
||||||
private String mDisplayContents;
|
private String title;
|
||||||
private String mTitle;
|
private BarcodeFormat format;
|
||||||
private BarcodeFormat mFormat;
|
|
||||||
|
|
||||||
public QRCodeEncoder(Activity activity, Intent intent) {
|
public QRCodeEncoder(Activity activity, Intent intent) {
|
||||||
mActivity = activity;
|
this.activity = activity;
|
||||||
if (!encodeContents(intent)) {
|
if (!encodeContents(intent)) {
|
||||||
throw new IllegalArgumentException("No valid data to encode.");
|
throw new IllegalArgumentException("No valid data to encode.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestBarcode(Handler handler, int pixelResolution) {
|
public void requestBarcode(Handler handler, int pixelResolution) {
|
||||||
Thread encodeThread = new EncodeThread(mContents, handler, pixelResolution,
|
Thread encodeThread = new EncodeThread(contents, handler, pixelResolution,
|
||||||
mFormat);
|
format);
|
||||||
encodeThread.start();
|
encodeThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getContents() {
|
public String getContents() {
|
||||||
return mContents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDisplayContents() {
|
public String getDisplayContents() {
|
||||||
return mDisplayContents;
|
return displayContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return mTitle;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFormat() {
|
public String getFormat() {
|
||||||
return mFormat.toString();
|
return format.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// It would be nice if the string encoding lived in the core ZXing library,
|
// It would be nice if the string encoding lived in the core ZXing library,
|
||||||
|
@ -82,59 +88,59 @@ public final class QRCodeEncoder {
|
||||||
if (type == null || type.length() == 0) {
|
if (type == null || type.length() == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mFormat = BarcodeFormat.QR_CODE;
|
this.format = BarcodeFormat.QR_CODE;
|
||||||
encodeQRCodeContents(intent, type);
|
encodeQRCodeContents(intent, type);
|
||||||
} else {
|
} else {
|
||||||
String data = intent.getStringExtra(Intents.Encode.DATA);
|
String data = intent.getStringExtra(Intents.Encode.DATA);
|
||||||
if (data != null && data.length() != 0) {
|
if (data != null && data.length() != 0) {
|
||||||
mContents = data;
|
contents = data;
|
||||||
mDisplayContents = data;
|
displayContents = data;
|
||||||
mTitle = mActivity.getString(R.string.contents_text);
|
title = activity.getString(R.string.contents_text);
|
||||||
if (format.equals(Contents.Format.CODE_128))
|
if (format.equals(Contents.Format.CODE_128))
|
||||||
mFormat = BarcodeFormat.CODE_128;
|
this.format = BarcodeFormat.CODE_128;
|
||||||
else if (format.equals(Contents.Format.CODE_39))
|
else if (format.equals(Contents.Format.CODE_39))
|
||||||
mFormat = BarcodeFormat.CODE_39;
|
this.format = BarcodeFormat.CODE_39;
|
||||||
else if (format.equals(Contents.Format.EAN_8))
|
else if (format.equals(Contents.Format.EAN_8))
|
||||||
mFormat = BarcodeFormat.EAN_8;
|
this.format = BarcodeFormat.EAN_8;
|
||||||
else if (format.equals(Contents.Format.EAN_13))
|
else if (format.equals(Contents.Format.EAN_13))
|
||||||
mFormat = BarcodeFormat.EAN_13;
|
this.format = BarcodeFormat.EAN_13;
|
||||||
else if (format.equals(Contents.Format.UPC_A))
|
else if (format.equals(Contents.Format.UPC_A))
|
||||||
mFormat = BarcodeFormat.UPC_A;
|
this.format = BarcodeFormat.UPC_A;
|
||||||
else if (format.equals(Contents.Format.UPC_E))
|
else if (format.equals(Contents.Format.UPC_E))
|
||||||
mFormat = BarcodeFormat.UPC_E;
|
this.format = BarcodeFormat.UPC_E;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mContents != null && mContents.length() > 0;
|
return contents != null && contents.length() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void encodeQRCodeContents(Intent intent, String type) {
|
private void encodeQRCodeContents(Intent intent, String type) {
|
||||||
if (type.equals(Contents.Type.TEXT)) {
|
if (type.equals(Contents.Type.TEXT)) {
|
||||||
String data = intent.getStringExtra(Intents.Encode.DATA);
|
String data = intent.getStringExtra(Intents.Encode.DATA);
|
||||||
if (data != null && data.length() > 0) {
|
if (data != null && data.length() > 0) {
|
||||||
mContents = data;
|
contents = data;
|
||||||
mDisplayContents = data;
|
displayContents = data;
|
||||||
mTitle = mActivity.getString(R.string.contents_text);
|
title = activity.getString(R.string.contents_text);
|
||||||
}
|
}
|
||||||
} else if (type.equals(Contents.Type.EMAIL)) {
|
} else if (type.equals(Contents.Type.EMAIL)) {
|
||||||
String data = intent.getStringExtra(Intents.Encode.DATA);
|
String data = intent.getStringExtra(Intents.Encode.DATA);
|
||||||
if (data != null && data.length() > 0) {
|
if (data != null && data.length() > 0) {
|
||||||
mContents = "mailto:" + data;
|
contents = "mailto:" + data;
|
||||||
mDisplayContents = data;
|
displayContents = data;
|
||||||
mTitle = mActivity.getString(R.string.contents_email);
|
title = activity.getString(R.string.contents_email);
|
||||||
}
|
}
|
||||||
} else if (type.equals(Contents.Type.PHONE)) {
|
} else if (type.equals(Contents.Type.PHONE)) {
|
||||||
String data = intent.getStringExtra(Intents.Encode.DATA);
|
String data = intent.getStringExtra(Intents.Encode.DATA);
|
||||||
if (data != null && data.length() > 0) {
|
if (data != null && data.length() > 0) {
|
||||||
mContents = "tel:" + data;
|
contents = "tel:" + data;
|
||||||
mDisplayContents = PhoneNumberUtils.formatNumber(data);
|
displayContents = PhoneNumberUtils.formatNumber(data);
|
||||||
mTitle = mActivity.getString(R.string.contents_phone);
|
title = activity.getString(R.string.contents_phone);
|
||||||
}
|
}
|
||||||
} else if (type.equals(Contents.Type.SMS)) {
|
} else if (type.equals(Contents.Type.SMS)) {
|
||||||
String data = intent.getStringExtra(Intents.Encode.DATA);
|
String data = intent.getStringExtra(Intents.Encode.DATA);
|
||||||
if (data != null && data.length() > 0) {
|
if (data != null && data.length() > 0) {
|
||||||
mContents = "sms:" + data;
|
contents = "sms:" + data;
|
||||||
mDisplayContents = PhoneNumberUtils.formatNumber(data);
|
displayContents = PhoneNumberUtils.formatNumber(data);
|
||||||
mTitle = mActivity.getString(R.string.contents_sms);
|
title = activity.getString(R.string.contents_sms);
|
||||||
}
|
}
|
||||||
} else if (type.equals(Contents.Type.CONTACT)) {
|
} else if (type.equals(Contents.Type.CONTACT)) {
|
||||||
Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
|
Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
|
||||||
|
@ -169,12 +175,12 @@ public final class QRCodeEncoder {
|
||||||
// Make sure we've encoded at least one field.
|
// Make sure we've encoded at least one field.
|
||||||
if (newDisplayContents.length() > 0) {
|
if (newDisplayContents.length() > 0) {
|
||||||
newContents.append(';');
|
newContents.append(';');
|
||||||
mContents = newContents.toString();
|
contents = newContents.toString();
|
||||||
mDisplayContents = newDisplayContents.toString();
|
displayContents = newDisplayContents.toString();
|
||||||
mTitle = mActivity.getString(R.string.contents_contact);
|
title = activity.getString(R.string.contents_contact);
|
||||||
} else {
|
} else {
|
||||||
mContents = null;
|
contents = null;
|
||||||
mDisplayContents = null;
|
displayContents = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (type.equals(Contents.Type.LOCATION)) {
|
} else if (type.equals(Contents.Type.LOCATION)) {
|
||||||
|
@ -184,36 +190,35 @@ public final class QRCodeEncoder {
|
||||||
float latitude = bundle.getFloat("LAT", Float.MAX_VALUE);
|
float latitude = bundle.getFloat("LAT", Float.MAX_VALUE);
|
||||||
float longitude = bundle.getFloat("LONG", Float.MAX_VALUE);
|
float longitude = bundle.getFloat("LONG", Float.MAX_VALUE);
|
||||||
if (latitude != Float.MAX_VALUE && longitude != Float.MAX_VALUE) {
|
if (latitude != Float.MAX_VALUE && longitude != Float.MAX_VALUE) {
|
||||||
mContents = "geo:" + latitude + ',' + longitude;
|
contents = "geo:" + latitude + ',' + longitude;
|
||||||
mDisplayContents = latitude + "," + longitude;
|
displayContents = latitude + "," + longitude;
|
||||||
mTitle = mActivity.getString(R.string.contents_location);
|
title = activity.getString(R.string.contents_location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class EncodeThread extends Thread {
|
private static final class EncodeThread extends Thread {
|
||||||
|
|
||||||
private static final String TAG = "EncodeThread";
|
private static final String TAG = "EncodeThread";
|
||||||
|
|
||||||
private final String mContents;
|
private final String contents;
|
||||||
private final Handler mHandler;
|
private final Handler handler;
|
||||||
private final int mPixelResolution;
|
private final int pixelResolution;
|
||||||
private final BarcodeFormat mFormat;
|
private final BarcodeFormat format;
|
||||||
|
|
||||||
EncodeThread(String contents, Handler handler, int pixelResolution,
|
EncodeThread(String contents, Handler handler, int pixelResolution,
|
||||||
BarcodeFormat format) {
|
BarcodeFormat format) {
|
||||||
mContents = contents;
|
this.contents = contents;
|
||||||
mHandler = handler;
|
this.handler = handler;
|
||||||
mPixelResolution = pixelResolution;
|
this.pixelResolution = pixelResolution;
|
||||||
mFormat = format;
|
this.format = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
ByteMatrix result = new MultiFormatWriter().encode(mContents,
|
ByteMatrix result = new MultiFormatWriter().encode(contents, format,
|
||||||
mFormat, mPixelResolution, mPixelResolution);
|
pixelResolution, pixelResolution);
|
||||||
int width = result.getWidth();
|
int width = result.getWidth();
|
||||||
int height = result.getHeight();
|
int height = result.getHeight();
|
||||||
byte[][] array = result.getArray();
|
byte[][] array = result.getArray();
|
||||||
|
@ -228,19 +233,18 @@ public final class QRCodeEncoder {
|
||||||
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||||
Message message = Message.obtain(mHandler, R.id.encode_succeeded);
|
Message message = Message.obtain(handler, R.id.encode_succeeded);
|
||||||
message.obj = bitmap;
|
message.obj = bitmap;
|
||||||
message.sendToTarget();
|
message.sendToTarget();
|
||||||
} catch (WriterException e) {
|
} catch (WriterException e) {
|
||||||
Log.e(TAG, e.toString());
|
Log.e(TAG, e.toString());
|
||||||
Message message = Message.obtain(mHandler, R.id.encode_failed);
|
Message message = Message.obtain(handler, R.id.encode_failed);
|
||||||
message.sendToTarget();
|
message.sendToTarget();
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
Log.e(TAG, e.toString());
|
Log.e(TAG, e.toString());
|
||||||
Message message = Message.obtain(mHandler, R.id.encode_failed);
|
Message message = Message.obtain(handler, R.id.encode_failed);
|
||||||
message.sendToTarget();
|
message.sendToTarget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,17 +48,53 @@ import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses Google Book Search to find a word or phrase in the requested book.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public final class SearchBookContentsActivity extends Activity {
|
public final class SearchBookContentsActivity extends Activity {
|
||||||
|
|
||||||
private static final String TAG = "SearchBookContents";
|
private static final String TAG = "SearchBookContents";
|
||||||
private static final String USER_AGENT = "ZXing (Android)";
|
private static final String USER_AGENT = "ZXing (Android)";
|
||||||
|
|
||||||
private NetworkThread mNetworkThread;
|
private NetworkThread networkThread;
|
||||||
private String mISBN;
|
private String isbn;
|
||||||
private EditText mQueryTextView;
|
private EditText queryTextView;
|
||||||
private Button mQueryButton;
|
private Button queryButton;
|
||||||
private ListView mResultListView;
|
private ListView resultListView;
|
||||||
private TextView mHeaderView;
|
private TextView headerView;
|
||||||
|
|
||||||
|
public final Handler handler = new Handler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
switch (message.what) {
|
||||||
|
case R.id.search_book_contents_succeeded:
|
||||||
|
handleSearchResults((JSONObject) message.obj);
|
||||||
|
resetForNewQuery();
|
||||||
|
break;
|
||||||
|
case R.id.search_book_contents_failed:
|
||||||
|
resetForNewQuery();
|
||||||
|
headerView.setText(R.string.msg_sbc_failed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final Button.OnClickListener buttonListener = new Button.OnClickListener() {
|
||||||
|
public void onClick(View view) {
|
||||||
|
launchSearch();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final View.OnKeyListener keyListener = new View.OnKeyListener() {
|
||||||
|
public boolean onKey(View view, int keyCode, KeyEvent event) {
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
||||||
|
launchSearch();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
|
@ -69,39 +105,38 @@ public final class SearchBookContentsActivity extends Activity {
|
||||||
CookieManager.getInstance().removeExpiredCookie();
|
CookieManager.getInstance().removeExpiredCookie();
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
if (intent == null || (!intent.getAction().equals(Intents.SearchBookContents.ACTION) &&
|
if (intent == null || (!intent.getAction().equals(Intents.SearchBookContents.ACTION))) {
|
||||||
!intent.getAction().equals(Intents.SearchBookContents.DEPRECATED_ACTION))) {
|
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mISBN = intent.getStringExtra(Intents.SearchBookContents.ISBN);
|
isbn = intent.getStringExtra(Intents.SearchBookContents.ISBN);
|
||||||
setTitle(getString(R.string.sbc_name) + ": ISBN " + mISBN);
|
setTitle(getString(R.string.sbc_name) + ": ISBN " + isbn);
|
||||||
|
|
||||||
setContentView(R.layout.search_book_contents);
|
setContentView(R.layout.search_book_contents);
|
||||||
mQueryTextView = (EditText) findViewById(R.id.query_text_view);
|
queryTextView = (EditText) findViewById(R.id.query_text_view);
|
||||||
|
|
||||||
String initialQuery = intent.getStringExtra(Intents.SearchBookContents.QUERY);
|
String initialQuery = intent.getStringExtra(Intents.SearchBookContents.QUERY);
|
||||||
if (initialQuery != null && initialQuery.length() > 0) {
|
if (initialQuery != null && initialQuery.length() > 0) {
|
||||||
// Populate the search box but don't trigger the search
|
// Populate the search box but don't trigger the search
|
||||||
mQueryTextView.setText(initialQuery);
|
queryTextView.setText(initialQuery);
|
||||||
}
|
}
|
||||||
mQueryTextView.setOnKeyListener(mKeyListener);
|
queryTextView.setOnKeyListener(keyListener);
|
||||||
|
|
||||||
mQueryButton = (Button) findViewById(R.id.query_button);
|
queryButton = (Button) findViewById(R.id.query_button);
|
||||||
mQueryButton.setOnClickListener(mButtonListener);
|
queryButton.setOnClickListener(buttonListener);
|
||||||
|
|
||||||
mResultListView = (ListView) findViewById(R.id.result_list_view);
|
resultListView = (ListView) findViewById(R.id.result_list_view);
|
||||||
LayoutInflater factory = LayoutInflater.from(this);
|
LayoutInflater factory = LayoutInflater.from(this);
|
||||||
mHeaderView = (TextView) factory.inflate(R.layout.search_book_contents_header,
|
headerView = (TextView) factory.inflate(R.layout.search_book_contents_header,
|
||||||
mResultListView, false);
|
resultListView, false);
|
||||||
mResultListView.addHeaderView(mHeaderView);
|
resultListView.addHeaderView(headerView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
mQueryTextView.selectAll();
|
queryTextView.selectAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -110,55 +145,23 @@ public final class SearchBookContentsActivity extends Activity {
|
||||||
super.onConfigurationChanged(config);
|
super.onConfigurationChanged(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Handler mHandler = new Handler() {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
switch (message.what) {
|
|
||||||
case R.id.search_book_contents_succeeded:
|
|
||||||
handleSearchResults((JSONObject) message.obj);
|
|
||||||
resetForNewQuery();
|
|
||||||
break;
|
|
||||||
case R.id.search_book_contents_failed:
|
|
||||||
resetForNewQuery();
|
|
||||||
mHeaderView.setText(R.string.msg_sbc_failed);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private void resetForNewQuery() {
|
private void resetForNewQuery() {
|
||||||
mNetworkThread = null;
|
networkThread = null;
|
||||||
mQueryTextView.setEnabled(true);
|
queryTextView.setEnabled(true);
|
||||||
mQueryTextView.selectAll();
|
queryTextView.selectAll();
|
||||||
mQueryButton.setEnabled(true);
|
queryButton.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Button.OnClickListener mButtonListener = new Button.OnClickListener() {
|
|
||||||
public void onClick(View view) {
|
|
||||||
launchSearch();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final View.OnKeyListener mKeyListener = new View.OnKeyListener() {
|
|
||||||
public boolean onKey(View view, int keyCode, KeyEvent event) {
|
|
||||||
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
|
||||||
launchSearch();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private void launchSearch() {
|
private void launchSearch() {
|
||||||
if (mNetworkThread == null) {
|
if (networkThread == null) {
|
||||||
String query = mQueryTextView.getText().toString();
|
String query = queryTextView.getText().toString();
|
||||||
if (query != null && query.length() > 0) {
|
if (query != null && query.length() > 0) {
|
||||||
mNetworkThread = new NetworkThread(mISBN, query, mHandler);
|
networkThread = new NetworkThread(isbn, query, handler);
|
||||||
mNetworkThread.start();
|
networkThread.start();
|
||||||
mHeaderView.setText(R.string.msg_sbc_searching_book);
|
headerView.setText(R.string.msg_sbc_searching_book);
|
||||||
mResultListView.setAdapter(null);
|
resultListView.setAdapter(null);
|
||||||
mQueryTextView.setEnabled(false);
|
queryTextView.setEnabled(false);
|
||||||
mQueryButton.setEnabled(false);
|
queryButton.setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,26 +171,26 @@ public final class SearchBookContentsActivity extends Activity {
|
||||||
private void handleSearchResults(JSONObject json) {
|
private void handleSearchResults(JSONObject json) {
|
||||||
try {
|
try {
|
||||||
int count = json.getInt("number_of_results");
|
int count = json.getInt("number_of_results");
|
||||||
mHeaderView.setText("Found " + (count == 1 ? "1 result" : count + " results"));
|
headerView.setText("Found " + (count == 1 ? "1 result" : count + " results"));
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
JSONArray results = json.getJSONArray("search_results");
|
JSONArray results = json.getJSONArray("search_results");
|
||||||
SearchBookContentsResult.setQuery(mQueryTextView.getText().toString());
|
SearchBookContentsResult.setQuery(queryTextView.getText().toString());
|
||||||
List<SearchBookContentsResult> items = new ArrayList<SearchBookContentsResult>(count);
|
List<SearchBookContentsResult> items = new ArrayList<SearchBookContentsResult>(count);
|
||||||
for (int x = 0; x < count; x++) {
|
for (int x = 0; x < count; x++) {
|
||||||
items.add(parseResult(results.getJSONObject(x)));
|
items.add(parseResult(results.getJSONObject(x)));
|
||||||
}
|
}
|
||||||
mResultListView.setAdapter(new SearchBookContentsAdapter(this, items));
|
resultListView.setAdapter(new SearchBookContentsAdapter(this, items));
|
||||||
} else {
|
} else {
|
||||||
String searchable = json.optString("searchable");
|
String searchable = json.optString("searchable");
|
||||||
if ("false".equals(searchable)) {
|
if ("false".equals(searchable)) {
|
||||||
mHeaderView.setText(R.string.msg_sbc_book_not_searchable);
|
headerView.setText(R.string.msg_sbc_book_not_searchable);
|
||||||
}
|
}
|
||||||
mResultListView.setAdapter(null);
|
resultListView.setAdapter(null);
|
||||||
}
|
}
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
Log.e(TAG, e.toString());
|
Log.e(TAG, e.toString());
|
||||||
mResultListView.setAdapter(null);
|
resultListView.setAdapter(null);
|
||||||
mHeaderView.setText(R.string.msg_sbc_failed);
|
headerView.setText(R.string.msg_sbc_failed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,15 +226,14 @@ public final class SearchBookContentsActivity extends Activity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class NetworkThread extends Thread {
|
private static final class NetworkThread extends Thread {
|
||||||
|
private final String isbn;
|
||||||
private final String mISBN;
|
private final String query;
|
||||||
private final String mQuery;
|
private final Handler handler;
|
||||||
private final Handler mHandler;
|
|
||||||
|
|
||||||
NetworkThread(String isbn, String query, Handler handler) {
|
NetworkThread(String isbn, String query, Handler handler) {
|
||||||
mISBN = isbn;
|
this.isbn = isbn;
|
||||||
mQuery = query;
|
this.query = query;
|
||||||
mHandler = handler;
|
this.handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -241,8 +243,8 @@ public final class SearchBookContentsActivity extends Activity {
|
||||||
// These return a JSON result which describes if and where the query was found. This API may
|
// These return a JSON result which describes if and where the query was found. This API may
|
||||||
// break or disappear at any time in the future. Since this is an API call rather than a
|
// break or disappear at any time in the future. Since this is an API call rather than a
|
||||||
// website, we don't use LocaleManager to change the TLD.
|
// website, we don't use LocaleManager to change the TLD.
|
||||||
URI uri = new URI("http", null, "www.google.com", -1, "/books", "vid=isbn" + mISBN +
|
URI uri = new URI("http", null, "www.google.com", -1, "/books", "vid=isbn" + isbn +
|
||||||
"&jscmd=SearchWithinVolume2&q=" + mQuery, null);
|
"&jscmd=SearchWithinVolume2&q=" + query, null);
|
||||||
HttpUriRequest get = new HttpGet(uri);
|
HttpUriRequest get = new HttpGet(uri);
|
||||||
get.setHeader("cookie", getCookie(uri.toString()));
|
get.setHeader("cookie", getCookie(uri.toString()));
|
||||||
client = AndroidHttpClient.newInstance(USER_AGENT);
|
client = AndroidHttpClient.newInstance(USER_AGENT);
|
||||||
|
@ -255,17 +257,17 @@ public final class SearchBookContentsActivity extends Activity {
|
||||||
JSONObject json = new JSONObject(jsonHolder.toString(getEncoding(entity)));
|
JSONObject json = new JSONObject(jsonHolder.toString(getEncoding(entity)));
|
||||||
jsonHolder.close();
|
jsonHolder.close();
|
||||||
|
|
||||||
Message message = Message.obtain(mHandler, R.id.search_book_contents_succeeded);
|
Message message = Message.obtain(handler, R.id.search_book_contents_succeeded);
|
||||||
message.obj = json;
|
message.obj = json;
|
||||||
message.sendToTarget();
|
message.sendToTarget();
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "HTTP returned " + response.getStatusLine().getStatusCode() + " for " + uri);
|
Log.e(TAG, "HTTP returned " + response.getStatusLine().getStatusCode() + " for " + uri);
|
||||||
Message message = Message.obtain(mHandler, R.id.search_book_contents_failed);
|
Message message = Message.obtain(handler, R.id.search_book_contents_failed);
|
||||||
message.sendToTarget();
|
message.sendToTarget();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, e.toString());
|
Log.e(TAG, e.toString());
|
||||||
Message message = Message.obtain(mHandler, R.id.search_book_contents_failed);
|
Message message = Message.obtain(handler, R.id.search_book_contents_failed);
|
||||||
message.sendToTarget();
|
message.sendToTarget();
|
||||||
} finally {
|
} finally {
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
|
@ -316,5 +318,4 @@ public final class SearchBookContentsActivity extends Activity {
|
||||||
// return "UTF-8";
|
// return "UTF-8";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,12 @@ import android.widget.ArrayAdapter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manufactures list items which represent SBC results.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public final class SearchBookContentsAdapter extends ArrayAdapter<SearchBookContentsResult> {
|
public final class SearchBookContentsAdapter extends ArrayAdapter<SearchBookContentsResult> {
|
||||||
|
|
||||||
public SearchBookContentsAdapter(Context context, List<SearchBookContentsResult> items) {
|
public SearchBookContentsAdapter(Context context, List<SearchBookContentsResult> items) {
|
||||||
super(context, R.layout.search_book_contents_list_item, 0, items);
|
super(context, R.layout.search_book_contents_list_item, 0, items);
|
||||||
}
|
}
|
||||||
|
@ -50,5 +54,4 @@ public final class SearchBookContentsAdapter extends ArrayAdapter<SearchBookCont
|
||||||
listItem.set(result);
|
listItem.set(result);
|
||||||
return listItem;
|
return listItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,14 @@ import android.util.AttributeSet;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list item which displays the page number and snippet of this search result.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public final class SearchBookContentsListItem extends LinearLayout {
|
public final class SearchBookContentsListItem extends LinearLayout {
|
||||||
|
private TextView pageNumberView;
|
||||||
private TextView mPageNumberView;
|
private TextView snippetView;
|
||||||
private TextView mSnippetView;
|
|
||||||
|
|
||||||
SearchBookContentsListItem(Context context) {
|
SearchBookContentsListItem(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
@ -41,12 +45,12 @@ public final class SearchBookContentsListItem extends LinearLayout {
|
||||||
@Override
|
@Override
|
||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
mPageNumberView = (TextView) findViewById(R.id.page_number_view);
|
pageNumberView = (TextView) findViewById(R.id.page_number_view);
|
||||||
mSnippetView = (TextView) findViewById(R.id.snippet_view);
|
snippetView = (TextView) findViewById(R.id.snippet_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(SearchBookContentsResult result) {
|
public void set(SearchBookContentsResult result) {
|
||||||
mPageNumberView.setText(result.getPageNumber());
|
pageNumberView.setText(result.getPageNumber());
|
||||||
String snippet = result.getSnippet();
|
String snippet = result.getSnippet();
|
||||||
if (snippet.length() > 0) {
|
if (snippet.length() > 0) {
|
||||||
if (result.getValidSnippet()) {
|
if (result.getValidSnippet()) {
|
||||||
|
@ -64,14 +68,13 @@ public final class SearchBookContentsListItem extends LinearLayout {
|
||||||
styledSnippet.setSpan(boldSpan, pos, pos + queryLength, 0);
|
styledSnippet.setSpan(boldSpan, pos, pos + queryLength, 0);
|
||||||
offset = pos + queryLength;
|
offset = pos + queryLength;
|
||||||
}
|
}
|
||||||
mSnippetView.setText(styledSnippet);
|
snippetView.setText(styledSnippet);
|
||||||
} else {
|
} else {
|
||||||
// This may be an error message, so don't try to bold the query terms within it
|
// This may be an error message, so don't try to bold the query terms within it
|
||||||
mSnippetView.setText(snippet);
|
snippetView.setText(snippet);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mSnippetView.setText("");
|
snippetView.setText("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,38 +16,41 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android;
|
package com.google.zxing.client.android;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The underlying data for a SBC result.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public final class SearchBookContentsResult {
|
public final class SearchBookContentsResult {
|
||||||
|
private static String query;
|
||||||
|
|
||||||
private static String sQuery;
|
private final String pageNumber;
|
||||||
|
private final String snippet;
|
||||||
private final String mPageNumber;
|
private final boolean validSnippet;
|
||||||
private final String mSnippet;
|
|
||||||
private final boolean mValidSnippet;
|
|
||||||
|
|
||||||
public SearchBookContentsResult(String pageNumber, String snippet, boolean validSnippet) {
|
public SearchBookContentsResult(String pageNumber, String snippet, boolean validSnippet) {
|
||||||
mPageNumber = pageNumber;
|
this.pageNumber = pageNumber;
|
||||||
mSnippet = snippet;
|
this.snippet = snippet;
|
||||||
mValidSnippet = validSnippet;
|
this.validSnippet = validSnippet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setQuery(String query) {
|
public static void setQuery(String query) {
|
||||||
sQuery = query;
|
SearchBookContentsResult.query = query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPageNumber() {
|
public String getPageNumber() {
|
||||||
return mPageNumber;
|
return pageNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSnippet() {
|
public String getSnippet() {
|
||||||
return mSnippet;
|
return snippet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getValidSnippet() {
|
public boolean getValidSnippet() {
|
||||||
return mValidSnippet;
|
return validSnippet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getQuery() {
|
public static String getQuery() {
|
||||||
return sQuery;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,13 @@ import android.text.ClipboardManager;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Barcode Scanner can share data like contacts and bookmarks by displaying a QR Code on screen,
|
||||||
|
* such that another user can scan the barcode with their phone.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public final class ShareActivity extends Activity {
|
public final class ShareActivity extends Activity {
|
||||||
|
|
||||||
private static final int PICK_BOOKMARK = 0;
|
private static final int PICK_BOOKMARK = 0;
|
||||||
private static final int PICK_CONTACT = 1;
|
private static final int PICK_CONTACT = 1;
|
||||||
|
|
||||||
|
@ -51,43 +56,16 @@ public final class ShareActivity extends Activity {
|
||||||
Contacts.PhonesColumns.NUMBER // 1
|
Contacts.PhonesColumns.NUMBER // 1
|
||||||
};
|
};
|
||||||
|
|
||||||
private Button mClipboardButton;
|
private Button clipboardButton;
|
||||||
|
|
||||||
@Override
|
private final Button.OnClickListener contactListener = new Button.OnClickListener() {
|
||||||
public void onCreate(Bundle icicle) {
|
|
||||||
super.onCreate(icicle);
|
|
||||||
setContentView(R.layout.share);
|
|
||||||
|
|
||||||
Button mContactButton = (Button) findViewById(R.id.contact_button);
|
|
||||||
mContactButton.setOnClickListener(mContactListener);
|
|
||||||
Button mBookmarkButton = (Button) findViewById(R.id.bookmark_button);
|
|
||||||
mBookmarkButton.setOnClickListener(mBookmarkListener);
|
|
||||||
mClipboardButton = (Button) findViewById(R.id.clipboard_button);
|
|
||||||
mClipboardButton.setOnClickListener(mClipboardListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
|
||||||
if (clipboard.hasText()) {
|
|
||||||
mClipboardButton.setEnabled(true);
|
|
||||||
mClipboardButton.setText(R.string.button_share_clipboard);
|
|
||||||
} else {
|
|
||||||
mClipboardButton.setEnabled(false);
|
|
||||||
mClipboardButton.setText(R.string.button_clipboard_empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Button.OnClickListener mContactListener = new Button.OnClickListener() {
|
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
startActivityForResult(new Intent(Intent.ACTION_PICK, Contacts.People.CONTENT_URI),
|
startActivityForResult(new Intent(Intent.ACTION_PICK, Contacts.People.CONTENT_URI),
|
||||||
PICK_CONTACT);
|
PICK_CONTACT);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final Button.OnClickListener mBookmarkListener = new Button.OnClickListener() {
|
private final Button.OnClickListener bookmarkListener = new Button.OnClickListener() {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent intent = new Intent(Intent.ACTION_PICK);
|
Intent intent = new Intent(Intent.ACTION_PICK);
|
||||||
intent.setClassName(ShareActivity.this, BookmarkPickerActivity.class.getName());
|
intent.setClassName(ShareActivity.this, BookmarkPickerActivity.class.getName());
|
||||||
|
@ -95,7 +73,7 @@ public final class ShareActivity extends Activity {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final Button.OnClickListener mClipboardListener = new Button.OnClickListener() {
|
private final Button.OnClickListener clipboardListener = new Button.OnClickListener() {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||||
// Should always be true, because we grey out the clipboard button in onResume() if it's empty
|
// Should always be true, because we grey out the clipboard button in onResume() if it's empty
|
||||||
|
@ -109,6 +87,33 @@ public final class ShareActivity extends Activity {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle icicle) {
|
||||||
|
super.onCreate(icicle);
|
||||||
|
setContentView(R.layout.share);
|
||||||
|
|
||||||
|
Button mContactButton = (Button) findViewById(R.id.contact_button);
|
||||||
|
mContactButton.setOnClickListener(contactListener);
|
||||||
|
Button mBookmarkButton = (Button) findViewById(R.id.bookmark_button);
|
||||||
|
mBookmarkButton.setOnClickListener(bookmarkListener);
|
||||||
|
clipboardButton = (Button) findViewById(R.id.clipboard_button);
|
||||||
|
clipboardButton.setOnClickListener(clipboardListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||||
|
if (clipboard.hasText()) {
|
||||||
|
clipboardButton.setEnabled(true);
|
||||||
|
clipboardButton.setText(R.string.button_share_clipboard);
|
||||||
|
} else {
|
||||||
|
clipboardButton.setEnabled(false);
|
||||||
|
clipboardButton.setText(R.string.button_clipboard_empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
|
@ -213,5 +218,4 @@ public final class ShareActivity extends Activity {
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,34 +28,35 @@ import android.view.View;
|
||||||
/**
|
/**
|
||||||
* This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
|
* This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
|
||||||
* transparency outside it, as well as the laser scanner animation and result points.
|
* transparency outside it, as well as the laser scanner animation and result points.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
*/
|
*/
|
||||||
public final class ViewfinderView extends View {
|
public final class ViewfinderView extends View {
|
||||||
|
|
||||||
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
|
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
|
||||||
private static final long ANIMATION_DELAY = 100L;
|
private static final long ANIMATION_DELAY = 100L;
|
||||||
|
|
||||||
private final Paint mPaint;
|
private final Paint paint;
|
||||||
private final Rect mBox;
|
private final Rect box;
|
||||||
private Bitmap mResultBitmap;
|
private Bitmap resultBitmap;
|
||||||
private final int mMaskColor;
|
private final int maskColor;
|
||||||
private final int mResultColor;
|
private final int resultColor;
|
||||||
private final int mFrameColor;
|
private final int frameColor;
|
||||||
private final int mLaserColor;
|
private final int laserColor;
|
||||||
private int mScannerAlpha;
|
private int scannerAlpha;
|
||||||
|
|
||||||
// This constructor is used when the class is built from an XML resource.
|
// This constructor is used when the class is built from an XML resource.
|
||||||
public ViewfinderView(Context context, AttributeSet attrs) {
|
public ViewfinderView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
|
||||||
// Initialize these once for performance rather than calling them every time in onDraw().
|
// Initialize these once for performance rather than calling them every time in onDraw().
|
||||||
mPaint = new Paint();
|
paint = new Paint();
|
||||||
mBox = new Rect();
|
box = new Rect();
|
||||||
Resources resources = getResources();
|
Resources resources = getResources();
|
||||||
mMaskColor = resources.getColor(R.color.viewfinder_mask);
|
maskColor = resources.getColor(R.color.viewfinder_mask);
|
||||||
mResultColor = resources.getColor(R.color.result_view);
|
resultColor = resources.getColor(R.color.result_view);
|
||||||
mFrameColor = resources.getColor(R.color.viewfinder_frame);
|
frameColor = resources.getColor(R.color.viewfinder_frame);
|
||||||
mLaserColor = resources.getColor(R.color.viewfinder_laser);
|
laserColor = resources.getColor(R.color.viewfinder_laser);
|
||||||
mScannerAlpha = 0;
|
scannerAlpha = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -65,48 +66,48 @@ public final class ViewfinderView extends View {
|
||||||
int height = canvas.getHeight();
|
int height = canvas.getHeight();
|
||||||
|
|
||||||
// Draw the exterior (i.e. outside the framing rect) darkened
|
// Draw the exterior (i.e. outside the framing rect) darkened
|
||||||
mPaint.setColor(mResultBitmap != null ? mResultColor : mMaskColor);
|
paint.setColor(resultBitmap != null ? resultColor : maskColor);
|
||||||
mBox.set(0, 0, width, frame.top);
|
box.set(0, 0, width, frame.top);
|
||||||
canvas.drawRect(mBox, mPaint);
|
canvas.drawRect(box, paint);
|
||||||
mBox.set(0, frame.top, frame.left, frame.bottom + 1);
|
box.set(0, frame.top, frame.left, frame.bottom + 1);
|
||||||
canvas.drawRect(mBox, mPaint);
|
canvas.drawRect(box, paint);
|
||||||
mBox.set(frame.right + 1, frame.top, width, frame.bottom + 1);
|
box.set(frame.right + 1, frame.top, width, frame.bottom + 1);
|
||||||
canvas.drawRect(mBox, mPaint);
|
canvas.drawRect(box, paint);
|
||||||
mBox.set(0, frame.bottom + 1, width, height);
|
box.set(0, frame.bottom + 1, width, height);
|
||||||
canvas.drawRect(mBox, mPaint);
|
canvas.drawRect(box, paint);
|
||||||
|
|
||||||
if (mResultBitmap != null) {
|
if (resultBitmap != null) {
|
||||||
// Draw the opaque result bitmap over the scanning rectangle
|
// Draw the opaque result bitmap over the scanning rectangle
|
||||||
mPaint.setAlpha(255);
|
paint.setAlpha(255);
|
||||||
canvas.drawBitmap(mResultBitmap, frame.left, frame.top, mPaint);
|
canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
|
||||||
} else {
|
} else {
|
||||||
// Draw a two pixel solid black border inside the framing rect
|
// Draw a two pixel solid black border inside the framing rect
|
||||||
mPaint.setColor(mFrameColor);
|
paint.setColor(frameColor);
|
||||||
mBox.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
|
box.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
|
||||||
canvas.drawRect(mBox, mPaint);
|
canvas.drawRect(box, paint);
|
||||||
mBox.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
|
box.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
|
||||||
canvas.drawRect(mBox, mPaint);
|
canvas.drawRect(box, paint);
|
||||||
mBox.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
|
box.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
|
||||||
canvas.drawRect(mBox, mPaint);
|
canvas.drawRect(box, paint);
|
||||||
mBox.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
|
box.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
|
||||||
canvas.drawRect(mBox, mPaint);
|
canvas.drawRect(box, paint);
|
||||||
|
|
||||||
// Draw a red "laser scanner" line through the middle to show decoding is active
|
// Draw a red "laser scanner" line through the middle to show decoding is active
|
||||||
mPaint.setColor(mLaserColor);
|
paint.setColor(laserColor);
|
||||||
mPaint.setAlpha(SCANNER_ALPHA[mScannerAlpha]);
|
paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
|
||||||
mScannerAlpha = (mScannerAlpha + 1) % SCANNER_ALPHA.length;
|
scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
|
||||||
int middle = frame.height() / 2 + frame.top;
|
int middle = frame.height() / 2 + frame.top;
|
||||||
mBox.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
|
box.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
|
||||||
canvas.drawRect(mBox, mPaint);
|
canvas.drawRect(box, paint);
|
||||||
|
|
||||||
// Request another update at the animation interval, but only repaint the laser line,
|
// Request another update at the animation interval, but only repaint the laser line,
|
||||||
// not the entire viewfinder mask.
|
// not the entire viewfinder mask.
|
||||||
postInvalidateDelayed(ANIMATION_DELAY, mBox.left, mBox.top, mBox.right, mBox.bottom);
|
postInvalidateDelayed(ANIMATION_DELAY, box.left, box.top, box.right, box.bottom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawViewfinder() {
|
public void drawViewfinder() {
|
||||||
mResultBitmap = null;
|
resultBitmap = null;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,8 +117,7 @@ public final class ViewfinderView extends View {
|
||||||
* @param barcode An image of the decoded barcode.
|
* @param barcode An image of the decoded barcode.
|
||||||
*/
|
*/
|
||||||
public void drawResultBitmap(Bitmap barcode) {
|
public void drawResultBitmap(Bitmap barcode) {
|
||||||
mResultBitmap = barcode;
|
resultBitmap = barcode;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,34 +16,39 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.telephony.PhoneNumberUtils;
|
|
||||||
import android.text.SpannableString;
|
|
||||||
import android.text.Spannable;
|
|
||||||
import android.text.style.StyleSpan;
|
|
||||||
import com.google.zxing.client.android.R;
|
import com.google.zxing.client.android.R;
|
||||||
import com.google.zxing.client.result.AddressBookParsedResult;
|
import com.google.zxing.client.result.AddressBookParsedResult;
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.telephony.PhoneNumberUtils;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.style.StyleSpan;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.ParsePosition;
|
import java.text.ParsePosition;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles address book entries.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public final class AddressBookResultHandler extends ResultHandler {
|
public final class AddressBookResultHandler extends ResultHandler {
|
||||||
|
|
||||||
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
|
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
|
||||||
|
|
||||||
private final boolean[] mFields;
|
private final boolean[] fields;
|
||||||
private int mButtonCount;
|
private int buttonCount;
|
||||||
|
|
||||||
// This takes all the work out of figuring out which buttons/actions should be in which
|
// This takes all the work out of figuring out which buttons/actions should be in which
|
||||||
// positions, based on which fields are present in this barcode.
|
// positions, based on which fields are present in this barcode.
|
||||||
private int mapIndexToAction(int index) {
|
private int mapIndexToAction(int index) {
|
||||||
if (index < mButtonCount) {
|
if (index < buttonCount) {
|
||||||
int count = -1;
|
int count = -1;
|
||||||
for (int x = 0; x < MAX_BUTTON_COUNT; x++) {
|
for (int x = 0; x < MAX_BUTTON_COUNT; x++) {
|
||||||
if (mFields[x]) {
|
if (fields[x]) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (count == index) {
|
if (count == index) {
|
||||||
|
@ -64,23 +69,23 @@ public final class AddressBookResultHandler extends ResultHandler {
|
||||||
String[] emails = addressResult.getEmails();
|
String[] emails = addressResult.getEmails();
|
||||||
boolean hasEmailAddress = emails != null && emails.length > 0;
|
boolean hasEmailAddress = emails != null && emails.length > 0;
|
||||||
|
|
||||||
mFields = new boolean[MAX_BUTTON_COUNT];
|
fields = new boolean[MAX_BUTTON_COUNT];
|
||||||
mFields[0] = true; // Add contact is always available
|
fields[0] = true; // Add contact is always available
|
||||||
mFields[1] = hasAddress;
|
fields[1] = hasAddress;
|
||||||
mFields[2] = hasPhoneNumber;
|
fields[2] = hasPhoneNumber;
|
||||||
mFields[3] = hasEmailAddress;
|
fields[3] = hasEmailAddress;
|
||||||
|
|
||||||
mButtonCount = 0;
|
buttonCount = 0;
|
||||||
for (int x = 0; x < MAX_BUTTON_COUNT; x++) {
|
for (int x = 0; x < MAX_BUTTON_COUNT; x++) {
|
||||||
if (mFields[x]) {
|
if (fields[x]) {
|
||||||
mButtonCount++;
|
buttonCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonCount() {
|
public int getButtonCount() {
|
||||||
return mButtonCount;
|
return buttonCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -102,7 +107,7 @@ public final class AddressBookResultHandler extends ResultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleButtonPress(int index) {
|
public void handleButtonPress(int index) {
|
||||||
AddressBookParsedResult addressResult = (AddressBookParsedResult) mResult;
|
AddressBookParsedResult addressResult = (AddressBookParsedResult) result;
|
||||||
int action = mapIndexToAction(index);
|
int action = mapIndexToAction(index);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -130,7 +135,7 @@ public final class AddressBookResultHandler extends ResultHandler {
|
||||||
// Overriden so we can hyphenate phone numbers, format birthdays, and bold the name.
|
// Overriden so we can hyphenate phone numbers, format birthdays, and bold the name.
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getDisplayContents() {
|
public CharSequence getDisplayContents() {
|
||||||
AddressBookParsedResult result = (AddressBookParsedResult) mResult;
|
AddressBookParsedResult result = (AddressBookParsedResult) this.result;
|
||||||
StringBuffer contents = new StringBuffer();
|
StringBuffer contents = new StringBuffer();
|
||||||
ParsedResult.maybeAppend(result.getNames(), contents);
|
ParsedResult.maybeAppend(result.getNames(), contents);
|
||||||
int namesLength = contents.length();
|
int namesLength = contents.length();
|
||||||
|
@ -178,5 +183,4 @@ public final class AddressBookResultHandler extends ResultHandler {
|
||||||
public int getDisplayTitle() {
|
public int getDisplayTitle() {
|
||||||
return R.string.result_address_book;
|
return R.string.result_address_book;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,57 +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.android.result;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
|
||||||
import com.google.zxing.client.result.ParsedResultType;
|
|
||||||
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link com.google.zxing.client.result.ParsedResult} derived from a URI that encodes an Android
|
|
||||||
* {@link Intent}, and which should presumably trigger that intent on Android.
|
|
||||||
*/
|
|
||||||
public final class AndroidIntentParsedResult extends ParsedResult {
|
|
||||||
|
|
||||||
private final Intent mIntent;
|
|
||||||
|
|
||||||
private AndroidIntentParsedResult(Intent intent) {
|
|
||||||
super(ParsedResultType.ANDROID_INTENT);
|
|
||||||
mIntent = intent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AndroidIntentParsedResult parse(String rawText) {
|
|
||||||
try {
|
|
||||||
return new AndroidIntentParsedResult(Intent.getIntent(rawText));
|
|
||||||
} catch (URISyntaxException urise) {
|
|
||||||
return null;
|
|
||||||
} catch (IllegalArgumentException iae) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Intent getIntent() {
|
|
||||||
return mIntent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDisplayResult() {
|
|
||||||
return mIntent.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -16,11 +16,12 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import com.google.zxing.client.android.R;
|
import com.google.zxing.client.android.R;
|
||||||
import com.google.zxing.client.result.CalendarParsedResult;
|
import com.google.zxing.client.result.CalendarParsedResult;
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.ParsePosition;
|
import java.text.ParsePosition;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
@ -28,12 +29,16 @@ import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles calendar entries encoded in QR Codes.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public final class CalendarResultHandler extends ResultHandler {
|
public final class CalendarResultHandler extends ResultHandler {
|
||||||
|
|
||||||
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
|
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
|
||||||
private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
|
private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
|
||||||
|
|
||||||
private static final int[] mButtons = {
|
private static final int[] buttons = {
|
||||||
R.string.button_add_calendar
|
R.string.button_add_calendar
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -43,17 +48,17 @@ public final class CalendarResultHandler extends ResultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonCount() {
|
public int getButtonCount() {
|
||||||
return mButtons.length;
|
return buttons.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonText(int index) {
|
public int getButtonText(int index) {
|
||||||
return mButtons[index];
|
return buttons[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleButtonPress(int index) {
|
public void handleButtonPress(int index) {
|
||||||
CalendarParsedResult calendarResult = (CalendarParsedResult) mResult;
|
CalendarParsedResult calendarResult = (CalendarParsedResult) result;
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
addCalendarEvent(calendarResult.getSummary(), calendarResult.getStart(),
|
addCalendarEvent(calendarResult.getSummary(), calendarResult.getStart(),
|
||||||
|
@ -64,7 +69,7 @@ public final class CalendarResultHandler extends ResultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getDisplayContents() {
|
public CharSequence getDisplayContents() {
|
||||||
CalendarParsedResult calResult = (CalendarParsedResult) mResult;
|
CalendarParsedResult calResult = (CalendarParsedResult) result;
|
||||||
StringBuffer result = new StringBuffer();
|
StringBuffer result = new StringBuffer();
|
||||||
ParsedResult.maybeAppend(calResult.getSummary(), result);
|
ParsedResult.maybeAppend(calResult.getSummary(), result);
|
||||||
appendTime(calResult.getStart(), result);
|
appendTime(calResult.getStart(), result);
|
||||||
|
@ -110,5 +115,4 @@ public final class CalendarResultHandler extends ResultHandler {
|
||||||
public int getDisplayTitle() {
|
public int getDisplayTitle() {
|
||||||
return R.string.result_calendar;
|
return R.string.result_calendar;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,19 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import com.google.zxing.client.android.R;
|
import com.google.zxing.client.android.R;
|
||||||
import com.google.zxing.client.result.EmailAddressParsedResult;
|
import com.google.zxing.client.result.EmailAddressParsedResult;
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
|
|
||||||
public final class EmailAddressResultHandler extends ResultHandler {
|
import android.app.Activity;
|
||||||
|
|
||||||
private static final int[] mButtons = {
|
/**
|
||||||
|
* Handles email addresses.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
public final class EmailAddressResultHandler extends ResultHandler {
|
||||||
|
private static final int[] buttons = {
|
||||||
R.string.button_email,
|
R.string.button_email,
|
||||||
R.string.button_add_contact
|
R.string.button_add_contact
|
||||||
};
|
};
|
||||||
|
@ -34,17 +39,17 @@ public final class EmailAddressResultHandler extends ResultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonCount() {
|
public int getButtonCount() {
|
||||||
return mButtons.length;
|
return buttons.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonText(int index) {
|
public int getButtonText(int index) {
|
||||||
return mButtons[index];
|
return buttons[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleButtonPress(int index) {
|
public void handleButtonPress(int index) {
|
||||||
EmailAddressParsedResult emailResult = (EmailAddressParsedResult) mResult;
|
EmailAddressParsedResult emailResult = (EmailAddressParsedResult) result;
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
sendEmailFromUri(emailResult.getMailtoURI(), null, null);
|
sendEmailFromUri(emailResult.getMailtoURI(), null, null);
|
||||||
|
@ -61,5 +66,4 @@ public final class EmailAddressResultHandler extends ResultHandler {
|
||||||
public int getDisplayTitle() {
|
public int getDisplayTitle() {
|
||||||
return R.string.result_email_address;
|
return R.string.result_email_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,19 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import com.google.zxing.client.android.R;
|
import com.google.zxing.client.android.R;
|
||||||
import com.google.zxing.client.result.GeoParsedResult;
|
import com.google.zxing.client.result.GeoParsedResult;
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
|
|
||||||
public final class GeoResultHandler extends ResultHandler {
|
import android.app.Activity;
|
||||||
|
|
||||||
private static final int[] mButtons = {
|
/**
|
||||||
|
* Handles geographic coordinates (typically encoded as geo: URLs).
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
public final class GeoResultHandler extends ResultHandler {
|
||||||
|
private static final int[] buttons = {
|
||||||
R.string.button_show_map,
|
R.string.button_show_map,
|
||||||
R.string.button_get_directions
|
R.string.button_get_directions
|
||||||
};
|
};
|
||||||
|
@ -34,17 +39,17 @@ public final class GeoResultHandler extends ResultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonCount() {
|
public int getButtonCount() {
|
||||||
return mButtons.length;
|
return buttons.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonText(int index) {
|
public int getButtonText(int index) {
|
||||||
return mButtons[index];
|
return buttons[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleButtonPress(int index) {
|
public void handleButtonPress(int index) {
|
||||||
GeoParsedResult geoResult = (GeoParsedResult) mResult;
|
GeoParsedResult geoResult = (GeoParsedResult) result;
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
openMap(geoResult.getGeoURI());
|
openMap(geoResult.getGeoURI());
|
||||||
|
@ -59,5 +64,4 @@ public final class GeoResultHandler extends ResultHandler {
|
||||||
public int getDisplayTitle() {
|
public int getDisplayTitle() {
|
||||||
return R.string.result_geo;
|
return R.string.result_geo;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,44 +16,50 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import com.google.zxing.client.android.R;
|
|
||||||
import com.google.zxing.client.android.PreferencesActivity;
|
import com.google.zxing.client.android.PreferencesActivity;
|
||||||
|
import com.google.zxing.client.android.R;
|
||||||
import com.google.zxing.client.result.ISBNParsedResult;
|
import com.google.zxing.client.result.ISBNParsedResult;
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
|
|
||||||
public final class ISBNResultHandler extends ResultHandler {
|
import android.app.Activity;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
private static final int[] mButtons = {
|
/**
|
||||||
|
* Handles books encoded by their ISBN values.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
public final class ISBNResultHandler extends ResultHandler {
|
||||||
|
private static final int[] buttons = {
|
||||||
R.string.button_product_search,
|
R.string.button_product_search,
|
||||||
R.string.button_book_search,
|
R.string.button_book_search,
|
||||||
R.string.button_search_book_contents,
|
R.string.button_search_book_contents,
|
||||||
R.string.button_custom_product_search,
|
R.string.button_custom_product_search,
|
||||||
};
|
};
|
||||||
|
|
||||||
private final String mCustomProductSearch;
|
private final String customProductSearch;
|
||||||
|
|
||||||
public ISBNResultHandler(Activity activity, ParsedResult result) {
|
public ISBNResultHandler(Activity activity, ParsedResult result) {
|
||||||
super(activity, result);
|
super(activity, result);
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||||
mCustomProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null);
|
customProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonCount() {
|
public int getButtonCount() {
|
||||||
return mCustomProductSearch != null && mCustomProductSearch.length() > 0 ? mButtons.length : mButtons.length - 1;
|
return customProductSearch != null && customProductSearch.length() > 0 ? buttons.length : buttons
|
||||||
|
.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonText(int index) {
|
public int getButtonText(int index) {
|
||||||
return mButtons[index];
|
return buttons[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleButtonPress(int index) {
|
public void handleButtonPress(int index) {
|
||||||
ISBNParsedResult isbnResult = (ISBNParsedResult) mResult;
|
ISBNParsedResult isbnResult = (ISBNParsedResult) result;
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
openProductSearch(isbnResult.getISBN());
|
openProductSearch(isbnResult.getISBN());
|
||||||
|
@ -65,7 +71,7 @@ public final class ISBNResultHandler extends ResultHandler {
|
||||||
searchBookContents(isbnResult.getISBN());
|
searchBookContents(isbnResult.getISBN());
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
String url = mCustomProductSearch.replace("%s", isbnResult.getISBN());
|
String url = customProductSearch.replace("%s", isbnResult.getISBN());
|
||||||
openURL(url);
|
openURL(url);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -75,5 +81,4 @@ public final class ISBNResultHandler extends ResultHandler {
|
||||||
public int getDisplayTitle() {
|
public int getDisplayTitle() {
|
||||||
return R.string.result_isbn;
|
return R.string.result_isbn;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,43 +16,48 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import com.google.zxing.client.android.R;
|
|
||||||
import com.google.zxing.client.android.PreferencesActivity;
|
import com.google.zxing.client.android.PreferencesActivity;
|
||||||
|
import com.google.zxing.client.android.R;
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
import com.google.zxing.client.result.ProductParsedResult;
|
import com.google.zxing.client.result.ProductParsedResult;
|
||||||
|
|
||||||
public final class ProductResultHandler extends ResultHandler {
|
import android.app.Activity;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
private static final int[] mButtons = {
|
/**
|
||||||
|
* Handles generic products which are not books.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
public final class ProductResultHandler extends ResultHandler {
|
||||||
|
private static final int[] buttons = {
|
||||||
R.string.button_product_search,
|
R.string.button_product_search,
|
||||||
R.string.button_web_search,
|
R.string.button_web_search,
|
||||||
R.string.button_custom_product_search,
|
R.string.button_custom_product_search,
|
||||||
};
|
};
|
||||||
|
|
||||||
private final String mCustomProductSearch;
|
private final String customProductSearch;
|
||||||
|
|
||||||
public ProductResultHandler(Activity activity, ParsedResult result) {
|
public ProductResultHandler(Activity activity, ParsedResult result) {
|
||||||
super(activity, result);
|
super(activity, result);
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||||
mCustomProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null);
|
customProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonCount() {
|
public int getButtonCount() {
|
||||||
return mCustomProductSearch != null ? mButtons.length : mButtons.length - 1;
|
return customProductSearch != null ? buttons.length : buttons.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonText(int index) {
|
public int getButtonText(int index) {
|
||||||
return mButtons[index];
|
return buttons[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleButtonPress(int index) {
|
public void handleButtonPress(int index) {
|
||||||
ProductParsedResult productResult = (ProductParsedResult) mResult;
|
ProductParsedResult productResult = (ProductParsedResult) result;
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
openProductSearch(productResult.getNormalizedProductID());
|
openProductSearch(productResult.getNormalizedProductID());
|
||||||
|
@ -61,7 +66,7 @@ public final class ProductResultHandler extends ResultHandler {
|
||||||
webSearch(productResult.getNormalizedProductID());
|
webSearch(productResult.getNormalizedProductID());
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
String url = mCustomProductSearch.replace("%s", productResult.getNormalizedProductID());
|
String url = customProductSearch.replace("%s", productResult.getNormalizedProductID());
|
||||||
openURL(url);
|
openURL(url);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -71,5 +76,4 @@ public final class ProductResultHandler extends ResultHandler {
|
||||||
public int getDisplayTitle() {
|
public int getDisplayTitle() {
|
||||||
return R.string.result_product;
|
return R.string.result_product;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,19 +22,19 @@ import android.widget.Button;
|
||||||
/**
|
/**
|
||||||
* Handles the result of barcode decoding in the context of the Android platform, by dispatching the
|
* Handles the result of barcode decoding in the context of the Android platform, by dispatching the
|
||||||
* proper intents to open other activities like GMail, Maps, etc.
|
* proper intents to open other activities like GMail, Maps, etc.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
*/
|
*/
|
||||||
public final class ResultButtonListener implements Button.OnClickListener {
|
public final class ResultButtonListener implements Button.OnClickListener {
|
||||||
|
final ResultHandler resultHandler;
|
||||||
final ResultHandler mResultHandler;
|
final int index;
|
||||||
final int mIndex;
|
|
||||||
|
|
||||||
public ResultButtonListener(ResultHandler resultHandler, int index) {
|
public ResultButtonListener(ResultHandler resultHandler, int index) {
|
||||||
mResultHandler = resultHandler;
|
this.resultHandler = resultHandler;
|
||||||
mIndex = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
mResultHandler.handleButtonPress(mIndex);
|
resultHandler.handleButtonPress(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,40 +16,50 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
|
import com.google.zxing.client.android.Contents;
|
||||||
|
import com.google.zxing.client.android.Intents;
|
||||||
|
import com.google.zxing.client.android.LocaleManager;
|
||||||
|
import com.google.zxing.client.android.R;
|
||||||
|
import com.google.zxing.client.android.SearchBookContentsActivity;
|
||||||
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
|
import com.google.zxing.client.result.ParsedResultType;
|
||||||
|
|
||||||
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.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.Contacts;
|
import android.provider.Contacts;
|
||||||
import com.google.zxing.client.android.Intents;
|
|
||||||
import com.google.zxing.client.android.R;
|
|
||||||
import com.google.zxing.client.android.SearchBookContentsActivity;
|
|
||||||
import com.google.zxing.client.android.LocaleManager;
|
|
||||||
import com.google.zxing.client.android.Contents;
|
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
|
||||||
import com.google.zxing.client.result.ParsedResultType;
|
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
import java.text.ParsePosition;
|
import java.text.ParsePosition;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class for the Android-specific barcode handlers. These allow the app to polymorphically
|
||||||
|
* suggest the appropriate actions for each data type.
|
||||||
|
*
|
||||||
|
* This class also contains a bunch of utility methods to take common actions like opening a URL.
|
||||||
|
* They could easily be moved into a helper object, but it can't be static because the Activity
|
||||||
|
* instance is needed to launch an intent.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
public abstract class ResultHandler {
|
public abstract class ResultHandler {
|
||||||
|
|
||||||
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
|
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
|
||||||
private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
|
private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
|
||||||
|
|
||||||
public static final int MAX_BUTTON_COUNT = 4;
|
public static final int MAX_BUTTON_COUNT = 4;
|
||||||
|
|
||||||
protected final ParsedResult mResult;
|
protected final ParsedResult result;
|
||||||
private final Activity mActivity;
|
private final Activity activity;
|
||||||
|
|
||||||
protected ResultHandler(Activity activity, ParsedResult result) {
|
protected ResultHandler(Activity activity, ParsedResult result) {
|
||||||
mResult = result;
|
this.result = result;
|
||||||
mActivity = activity;
|
this.activity = activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,7 +91,7 @@ public abstract class ResultHandler {
|
||||||
* @return The text to be displayed.
|
* @return The text to be displayed.
|
||||||
*/
|
*/
|
||||||
public CharSequence getDisplayContents() {
|
public CharSequence getDisplayContents() {
|
||||||
String contents = mResult.getDisplayResult();
|
String contents = result.getDisplayResult();
|
||||||
return contents.replace("\r", "");
|
return contents.replace("\r", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +108,7 @@ public abstract class ResultHandler {
|
||||||
* @return The parsed type, e.g. URI or ISBN
|
* @return The parsed type, e.g. URI or ISBN
|
||||||
*/
|
*/
|
||||||
public final ParsedResultType getType() {
|
public final ParsedResultType getType() {
|
||||||
return mResult.getType();
|
return result.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -171,7 +181,7 @@ public abstract class ResultHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void shareByEmail(String contents) {
|
public final void shareByEmail(String contents) {
|
||||||
sendEmailFromUri("mailto:", mActivity.getString(R.string.msg_share_subject_line), contents);
|
sendEmailFromUri("mailto:", activity.getString(R.string.msg_share_subject_line), contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void sendEmail(String address, String subject, String body) {
|
public final void sendEmail(String address, String subject, String body) {
|
||||||
|
@ -188,7 +198,7 @@ public abstract class ResultHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void shareBySMS(String contents) {
|
public final void shareBySMS(String contents) {
|
||||||
sendSMSFromUri("smsto:", mActivity.getString(R.string.msg_share_subject_line) + ":\n" +
|
sendSMSFromUri("smsto:", activity.getString(R.string.msg_share_subject_line) + ":\n" +
|
||||||
contents);
|
contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +222,7 @@ public abstract class ResultHandler {
|
||||||
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri));
|
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri));
|
||||||
// The Messaging app needs to see a valid subject or else it will treat this an an SMS.
|
// The Messaging app needs to see a valid subject or else it will treat this an an SMS.
|
||||||
if (subject == null || subject.length() == 0) {
|
if (subject == null || subject.length() == 0) {
|
||||||
putExtra(intent, "subject", mActivity.getString(R.string.msg_default_mms_subject));
|
putExtra(intent, "subject", activity.getString(R.string.msg_default_mms_subject));
|
||||||
} else {
|
} else {
|
||||||
putExtra(intent, "subject", subject);
|
putExtra(intent, "subject", subject);
|
||||||
}
|
}
|
||||||
|
@ -267,7 +277,7 @@ public abstract class ResultHandler {
|
||||||
|
|
||||||
public final void searchBookContents(String isbn) {
|
public final void searchBookContents(String isbn) {
|
||||||
Intent intent = new Intent(Intents.SearchBookContents.ACTION);
|
Intent intent = new Intent(Intents.SearchBookContents.ACTION);
|
||||||
intent.setClassName(mActivity, SearchBookContentsActivity.class.getName());
|
intent.setClassName(activity, SearchBookContentsActivity.class.getName());
|
||||||
putExtra(intent, Intents.SearchBookContents.ISBN, isbn);
|
putExtra(intent, Intents.SearchBookContents.ISBN, isbn);
|
||||||
launchIntent(intent);
|
launchIntent(intent);
|
||||||
}
|
}
|
||||||
|
@ -285,11 +295,11 @@ public abstract class ResultHandler {
|
||||||
private void launchIntent(Intent intent) {
|
private void launchIntent(Intent intent) {
|
||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
try {
|
try {
|
||||||
mActivity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
builder.setTitle(mActivity.getString(R.string.app_name));
|
builder.setTitle(activity.getString(R.string.app_name));
|
||||||
builder.setMessage(mActivity.getString(R.string.msg_intent_failed));
|
builder.setMessage(activity.getString(R.string.msg_intent_failed));
|
||||||
builder.setPositiveButton(R.string.button_ok, null);
|
builder.setPositiveButton(R.string.button_ok, null);
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
@ -301,5 +311,4 @@ public abstract class ResultHandler {
|
||||||
intent.putExtra(key, value);
|
intent.putExtra(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,19 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
import com.google.zxing.client.result.ParsedResultType;
|
import com.google.zxing.client.result.ParsedResultType;
|
||||||
import com.google.zxing.client.result.ResultParser;
|
import com.google.zxing.client.result.ResultParser;
|
||||||
|
|
||||||
public final class ResultHandlerFactory {
|
import android.app.Activity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manufactures Android-specific handlers based on the barcode content's type.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
public final class ResultHandlerFactory {
|
||||||
private ResultHandlerFactory() {
|
private ResultHandlerFactory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,22 +62,6 @@ public final class ResultHandlerFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ParsedResult parseResult(Result rawResult) {
|
private static ParsedResult parseResult(Result rawResult) {
|
||||||
ParsedResult result = ResultParser.parseResult(rawResult);
|
return ResultParser.parseResult(rawResult);
|
||||||
|
|
||||||
// Disabled for now. To reactivate, create an AndroidIntentResultHandler.
|
|
||||||
// if (result.getType().equals(ParsedResultType.TEXT)) {
|
|
||||||
// String rawText = rawResult.getText();
|
|
||||||
// AndroidIntentParsedResult androidResult = AndroidIntentParsedResult.parse(rawText);
|
|
||||||
// if (androidResult != null) {
|
|
||||||
// Intent intent = androidResult.getIntent();
|
|
||||||
// if (!Intent.ACTION_VIEW.equals(intent.getAction())) {
|
|
||||||
// // For now, don't take anything that just parses as a View action. A lot
|
|
||||||
// // of things are accepted as a View action by default.
|
|
||||||
// result = androidResult;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,20 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.telephony.PhoneNumberUtils;
|
|
||||||
import com.google.zxing.client.android.R;
|
import com.google.zxing.client.android.R;
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
import com.google.zxing.client.result.SMSParsedResult;
|
import com.google.zxing.client.result.SMSParsedResult;
|
||||||
|
|
||||||
public final class SMSResultHandler extends ResultHandler {
|
import android.app.Activity;
|
||||||
|
import android.telephony.PhoneNumberUtils;
|
||||||
|
|
||||||
private static final int[] mButtons = {
|
/**
|
||||||
|
* Handles SMS addresses, offering a choice of composing a new SMS or MMS message.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
public final class SMSResultHandler extends ResultHandler {
|
||||||
|
private static final int[] buttons = {
|
||||||
R.string.button_sms,
|
R.string.button_sms,
|
||||||
R.string.button_mms
|
R.string.button_mms
|
||||||
};
|
};
|
||||||
|
@ -35,17 +40,17 @@ public final class SMSResultHandler extends ResultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonCount() {
|
public int getButtonCount() {
|
||||||
return mButtons.length;
|
return buttons.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonText(int index) {
|
public int getButtonText(int index) {
|
||||||
return mButtons[index];
|
return buttons[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleButtonPress(int index) {
|
public void handleButtonPress(int index) {
|
||||||
SMSParsedResult smsResult = (SMSParsedResult) mResult;
|
SMSParsedResult smsResult = (SMSParsedResult) result;
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
sendSMS(smsResult.getNumber(), smsResult.getBody());
|
sendSMS(smsResult.getNumber(), smsResult.getBody());
|
||||||
|
@ -58,7 +63,7 @@ public final class SMSResultHandler extends ResultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getDisplayContents() {
|
public CharSequence getDisplayContents() {
|
||||||
SMSParsedResult smsResult = (SMSParsedResult) mResult;
|
SMSParsedResult smsResult = (SMSParsedResult) result;
|
||||||
StringBuffer contents = new StringBuffer();
|
StringBuffer contents = new StringBuffer();
|
||||||
ParsedResult.maybeAppend(PhoneNumberUtils.formatNumber(smsResult.getNumber()), contents);
|
ParsedResult.maybeAppend(PhoneNumberUtils.formatNumber(smsResult.getNumber()), contents);
|
||||||
ParsedResult.maybeAppend(smsResult.getVia(), contents);
|
ParsedResult.maybeAppend(smsResult.getVia(), contents);
|
||||||
|
@ -72,5 +77,4 @@ public final class SMSResultHandler extends ResultHandler {
|
||||||
public int getDisplayTitle() {
|
public int getDisplayTitle() {
|
||||||
return R.string.result_sms;
|
return R.string.result_sms;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,20 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.telephony.PhoneNumberUtils;
|
|
||||||
import com.google.zxing.client.android.R;
|
import com.google.zxing.client.android.R;
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
import com.google.zxing.client.result.TelParsedResult;
|
import com.google.zxing.client.result.TelParsedResult;
|
||||||
|
|
||||||
public final class TelResultHandler extends ResultHandler {
|
import android.app.Activity;
|
||||||
|
import android.telephony.PhoneNumberUtils;
|
||||||
|
|
||||||
private static final int[] mButtons = {
|
/**
|
||||||
|
* Offers relevant actions for telephone numbers.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
public final class TelResultHandler extends ResultHandler {
|
||||||
|
private static final int[] buttons = {
|
||||||
R.string.button_dial,
|
R.string.button_dial,
|
||||||
R.string.button_add_contact
|
R.string.button_add_contact
|
||||||
};
|
};
|
||||||
|
@ -35,17 +40,17 @@ public final class TelResultHandler extends ResultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonCount() {
|
public int getButtonCount() {
|
||||||
return mButtons.length;
|
return buttons.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonText(int index) {
|
public int getButtonText(int index) {
|
||||||
return mButtons[index];
|
return buttons[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleButtonPress(int index) {
|
public void handleButtonPress(int index) {
|
||||||
TelParsedResult telResult = (TelParsedResult) mResult;
|
TelParsedResult telResult = (TelParsedResult) result;
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
dialPhoneFromUri(telResult.getTelURI());
|
dialPhoneFromUri(telResult.getTelURI());
|
||||||
|
@ -61,7 +66,7 @@ public final class TelResultHandler extends ResultHandler {
|
||||||
// Overriden so we can take advantage of Android's phone number hyphenation routines.
|
// Overriden so we can take advantage of Android's phone number hyphenation routines.
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getDisplayContents() {
|
public CharSequence getDisplayContents() {
|
||||||
String contents = mResult.getDisplayResult();
|
String contents = result.getDisplayResult();
|
||||||
contents = contents.replace("\r", "");
|
contents = contents.replace("\r", "");
|
||||||
return PhoneNumberUtils.formatNumber(contents);
|
return PhoneNumberUtils.formatNumber(contents);
|
||||||
}
|
}
|
||||||
|
@ -70,5 +75,4 @@ public final class TelResultHandler extends ResultHandler {
|
||||||
public int getDisplayTitle() {
|
public int getDisplayTitle() {
|
||||||
return R.string.result_tel;
|
return R.string.result_tel;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,16 +16,18 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import com.google.zxing.client.android.R;
|
import com.google.zxing.client.android.R;
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class handles TextParsedResult as well as unknown formats.
|
* This class handles TextParsedResult as well as unknown formats. It's the fallback handler.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
*/
|
*/
|
||||||
public final class TextResultHandler extends ResultHandler {
|
public final class TextResultHandler extends ResultHandler {
|
||||||
|
private static final int[] buttons = {
|
||||||
private static final int[] mButtons = {
|
|
||||||
R.string.button_web_search,
|
R.string.button_web_search,
|
||||||
R.string.button_share_by_email,
|
R.string.button_share_by_email,
|
||||||
R.string.button_share_by_sms
|
R.string.button_share_by_sms
|
||||||
|
@ -37,25 +39,25 @@ public final class TextResultHandler extends ResultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonCount() {
|
public int getButtonCount() {
|
||||||
return mButtons.length;
|
return buttons.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonText(int index) {
|
public int getButtonText(int index) {
|
||||||
return mButtons[index];
|
return buttons[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleButtonPress(int index) {
|
public void handleButtonPress(int index) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
webSearch(mResult.getDisplayResult());
|
webSearch(result.getDisplayResult());
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
shareByEmail(mResult.getDisplayResult());
|
shareByEmail(result.getDisplayResult());
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
shareBySMS(mResult.getDisplayResult());
|
shareBySMS(result.getDisplayResult());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,5 +66,4 @@ public final class TextResultHandler extends ResultHandler {
|
||||||
public int getDisplayTitle() {
|
public int getDisplayTitle() {
|
||||||
return R.string.result_text;
|
return R.string.result_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,19 @@
|
||||||
|
|
||||||
package com.google.zxing.client.android.result;
|
package com.google.zxing.client.android.result;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import com.google.zxing.client.android.R;
|
import com.google.zxing.client.android.R;
|
||||||
import com.google.zxing.client.result.ParsedResult;
|
import com.google.zxing.client.result.ParsedResult;
|
||||||
import com.google.zxing.client.result.URIParsedResult;
|
import com.google.zxing.client.result.URIParsedResult;
|
||||||
|
|
||||||
public final class URIResultHandler extends ResultHandler {
|
import android.app.Activity;
|
||||||
|
|
||||||
private static final int[] mButtons = {
|
/**
|
||||||
|
* Offers appropriate actions for URLS.
|
||||||
|
*
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
public final class URIResultHandler extends ResultHandler {
|
||||||
|
private static final int[] buttons = {
|
||||||
R.string.button_open_browser,
|
R.string.button_open_browser,
|
||||||
R.string.button_share_by_email,
|
R.string.button_share_by_email,
|
||||||
R.string.button_share_by_sms
|
R.string.button_share_by_sms
|
||||||
|
@ -35,17 +40,17 @@ public final class URIResultHandler extends ResultHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonCount() {
|
public int getButtonCount() {
|
||||||
return mButtons.length;
|
return buttons.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButtonText(int index) {
|
public int getButtonText(int index) {
|
||||||
return mButtons[index];
|
return buttons[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleButtonPress(int index) {
|
public void handleButtonPress(int index) {
|
||||||
URIParsedResult uriResult = (URIParsedResult) mResult;
|
URIParsedResult uriResult = (URIParsedResult) result;
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
openURL(uriResult.getURI());
|
openURL(uriResult.getURI());
|
||||||
|
@ -63,5 +68,4 @@ public final class URIResultHandler extends ResultHandler {
|
||||||
public int getDisplayTitle() {
|
public int getDisplayTitle() {
|
||||||
return R.string.result_uri;
|
return R.string.result_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue