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. -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.zxing.client.android"
|
||||
android:versionName="2.93"
|
||||
android:versionCode="30">
|
||||
android:versionName="3.0 alpha1"
|
||||
android:versionCode="32">
|
||||
<!-- Allows this app to run on Cupcake devices. -->
|
||||
<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"
|
||||
android:label="@string/app_name">
|
||||
<activity android:name=".CaptureActivity"
|
||||
|
|
|
@ -8,4 +8,4 @@
|
|||
# project structure.
|
||||
|
||||
# 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
|
||||
* 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 {
|
||||
|
||||
private static final String[] BOOKMARK_PROJECTION = {
|
||||
Browser.BookmarkColumns.TITLE,
|
||||
Browser.BookmarkColumns.URL
|
||||
|
@ -48,32 +49,31 @@ public final class BookmarkPickerActivity extends ListActivity {
|
|||
// Without this selection, we'd get all the history entries too
|
||||
private static final String BOOKMARK_SELECTION = "bookmark = 1";
|
||||
|
||||
private Cursor mCursor;
|
||||
private Cursor cursor;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
mCursor = getContentResolver().query(Browser.BOOKMARKS_URI, BOOKMARK_PROJECTION,
|
||||
cursor = getContentResolver().query(Browser.BOOKMARKS_URI, BOOKMARK_PROJECTION,
|
||||
BOOKMARK_SELECTION, null, null);
|
||||
startManagingCursor(mCursor);
|
||||
startManagingCursor(cursor);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(ListView l, View view, int position, long id) {
|
||||
if (mCursor.moveToPosition(position)) {
|
||||
if (cursor.moveToPosition(position)) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(Browser.BookmarkColumns.TITLE, mCursor.getString(TITLE_COLUMN));
|
||||
intent.putExtra(Browser.BookmarkColumns.URL, mCursor.getString(URL_COLUMN));
|
||||
intent.putExtra(Browser.BookmarkColumns.TITLE, cursor.getString(TITLE_COLUMN));
|
||||
intent.putExtra(Browser.BookmarkColumns.URL, cursor.getString(URL_COLUMN));
|
||||
setResult(RESULT_OK, intent);
|
||||
} else {
|
||||
setResult(RESULT_CANCELED);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package com.google.zxing.client.android;
|
|||
import com.google.zxing.ResultPoint;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
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
|
||||
* implementation encapsulates the steps needed to take preview-sized images, which are used for
|
||||
* both preview and decoding.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
final class CameraManager {
|
||||
|
||||
private static final String TAG = "CameraManager";
|
||||
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 Camera mCamera;
|
||||
private final Context mContext;
|
||||
private Point mScreenResolution;
|
||||
private Rect mFramingRect;
|
||||
private Handler mPreviewHandler;
|
||||
private int mPreviewMessage;
|
||||
private Handler mAutoFocusHandler;
|
||||
private int mAutoFocusMessage;
|
||||
private boolean mInitialized;
|
||||
private boolean mPreviewing;
|
||||
private static CameraManager cameraManager;
|
||||
private Camera camera;
|
||||
private final Context context;
|
||||
private Point screenResolution;
|
||||
private Point cameraResolution;
|
||||
private Rect framingRect;
|
||||
private Handler previewHandler;
|
||||
private int previewMessage;
|
||||
private Handler autoFocusHandler;
|
||||
private int autoFocusMessage;
|
||||
private boolean initialized;
|
||||
private boolean previewing;
|
||||
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) {
|
||||
if (mCameraManager == null) {
|
||||
mCameraManager = new CameraManager(context);
|
||||
if (cameraManager == null) {
|
||||
cameraManager = new CameraManager(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static CameraManager get() {
|
||||
return mCameraManager;
|
||||
return cameraManager;
|
||||
}
|
||||
|
||||
private CameraManager(Context context) {
|
||||
mContext = context;
|
||||
mCamera = null;
|
||||
mInitialized = false;
|
||||
mPreviewing = false;
|
||||
this.context = context;
|
||||
camera = null;
|
||||
initialized = false;
|
||||
previewing = false;
|
||||
}
|
||||
|
||||
public void openDriver(SurfaceHolder holder) throws IOException {
|
||||
if (mCamera == null) {
|
||||
mCamera = Camera.open();
|
||||
mCamera.setPreviewDisplay(holder);
|
||||
if (camera == null) {
|
||||
camera = Camera.open();
|
||||
camera.setPreviewDisplay(holder);
|
||||
|
||||
if (!mInitialized) {
|
||||
mInitialized = true;
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
getScreenResolution();
|
||||
}
|
||||
|
||||
|
@ -84,26 +120,26 @@ final class CameraManager {
|
|||
}
|
||||
|
||||
public void closeDriver() {
|
||||
if (mCamera != null) {
|
||||
mCamera.release();
|
||||
mCamera = null;
|
||||
if (camera != null) {
|
||||
camera.release();
|
||||
camera = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void startPreview() {
|
||||
if (mCamera != null && !mPreviewing) {
|
||||
mCamera.startPreview();
|
||||
mPreviewing = true;
|
||||
if (camera != null && !previewing) {
|
||||
camera.startPreview();
|
||||
previewing = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void stopPreview() {
|
||||
if (mCamera != null && mPreviewing) {
|
||||
mCamera.setPreviewCallback(null);
|
||||
mCamera.stopPreview();
|
||||
mPreviewHandler = null;
|
||||
mAutoFocusHandler = null;
|
||||
mPreviewing = false;
|
||||
if (camera != null && previewing) {
|
||||
camera.setPreviewCallback(null);
|
||||
camera.stopPreview();
|
||||
previewHandler = null;
|
||||
autoFocusHandler = null;
|
||||
previewing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,39 +152,48 @@ final class CameraManager {
|
|||
* @param message The what field of the message to be sent.
|
||||
*/
|
||||
public void requestPreviewFrame(Handler handler, int message) {
|
||||
if (mCamera != null && mPreviewing) {
|
||||
mPreviewHandler = handler;
|
||||
mPreviewMessage = message;
|
||||
mCamera.setPreviewCallback(previewCallback);
|
||||
if (camera != null && previewing) {
|
||||
previewHandler = handler;
|
||||
previewMessage = message;
|
||||
camera.setPreviewCallback(previewCallback);
|
||||
}
|
||||
}
|
||||
|
||||
public void requestAutoFocus(Handler handler, int message) {
|
||||
if (mCamera != null && mPreviewing) {
|
||||
mAutoFocusHandler = handler;
|
||||
mAutoFocusMessage = message;
|
||||
mCamera.autoFocus(autoFocusCallback);
|
||||
if (camera != null && previewing) {
|
||||
autoFocusHandler = handler;
|
||||
autoFocusMessage = message;
|
||||
camera.autoFocus(autoFocusCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the framing rect which the UI should draw to show the user where to place the
|
||||
* barcode. The actual captured image should be a bit larger than indicated because they might
|
||||
* frame the shot too tightly. This target helps with alignment as well as forces the user to hold
|
||||
* the device far enough away to ensure the image will be in focus.
|
||||
* barcode. This target helps with alignment as well as forces the user to hold the device
|
||||
* far enough away to ensure the image will be in focus.
|
||||
*
|
||||
* @return The rectangle to draw on screen in window coordinates.
|
||||
*/
|
||||
public Rect getFramingRect() {
|
||||
if (mFramingRect == null) {
|
||||
int size = (mScreenResolution.x < mScreenResolution.y ? mScreenResolution.x :
|
||||
mScreenResolution.y) * 3 / 4;
|
||||
int leftOffset = (mScreenResolution.x - size) / 2;
|
||||
int topOffset = (mScreenResolution.y - size) / 2;
|
||||
mFramingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size);
|
||||
Log.v(TAG, "Calculated framing rect: " + mFramingRect);
|
||||
if (framingRect == null) {
|
||||
int width = cameraResolution.x * 3 / 4;
|
||||
if (width < MIN_FRAME_WIDTH) {
|
||||
width = MIN_FRAME_WIDTH;
|
||||
} else if (width > MAX_FRAME_WIDTH) {
|
||||
width = MAX_FRAME_WIDTH;
|
||||
}
|
||||
int height = cameraResolution.y * 3 / 4;
|
||||
if (height < MIN_FRAME_HEIGHT) {
|
||||
height = MIN_FRAME_HEIGHT;
|
||||
} else if (height > MAX_FRAME_HEIGHT) {
|
||||
height = MAX_FRAME_HEIGHT;
|
||||
}
|
||||
int leftOffset = (cameraResolution.x - width) / 2;
|
||||
int topOffset = (cameraResolution.y - height) / 2;
|
||||
framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
|
||||
Log.v(TAG, "Calculated framing rect: " + framingRect);
|
||||
}
|
||||
return 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
|
||||
* clear the handler so it will only receive one message.
|
||||
* A factory method to build the appropriate LuminanceSource object based on the format
|
||||
* 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 void onPreviewFrame(byte[] data, Camera camera) {
|
||||
camera.setPreviewCallback(null);
|
||||
if (mPreviewHandler != null) {
|
||||
Message message = mPreviewHandler.obtainMessage(mPreviewMessage, mScreenResolution.x,
|
||||
mScreenResolution.y, data);
|
||||
message.sendToTarget();
|
||||
mPreviewHandler = null;
|
||||
}
|
||||
public BaseLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
|
||||
Rect rect = getFramingRect();
|
||||
switch (previewFormat) {
|
||||
case PixelFormat.YCbCr_420_SP:
|
||||
case PixelFormat.YCbCr_422_SP:
|
||||
return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
|
||||
rect.width(), rect.height());
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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().
|
||||
*/
|
||||
private void setCameraParameters() {
|
||||
Camera.Parameters parameters = mCamera.getParameters();
|
||||
Camera.Parameters parameters = camera.getParameters();
|
||||
Camera.Size size = parameters.getPreviewSize();
|
||||
Log.v(TAG, "Default preview size: " + size.width + ", " + size.height);
|
||||
Log.v(TAG, "Default preview format: " + parameters.getPreviewFormat());
|
||||
Log.v(TAG, "Setting preview size: " + mScreenResolution.x + ", " + mScreenResolution.y);
|
||||
previewFormat = parameters.getPreviewFormat();
|
||||
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.
|
||||
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.
|
||||
parameters.set("flash-mode", "off");
|
||||
|
||||
mCamera.setParameters(parameters);
|
||||
camera.setParameters(parameters);
|
||||
}
|
||||
|
||||
private Point getScreenResolution() {
|
||||
if (mScreenResolution == null) {
|
||||
WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
|
||||
if (screenResolution == null) {
|
||||
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
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;
|
||||
|
||||
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.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
|
@ -54,20 +60,16 @@ import android.view.WindowManager;
|
|||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
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;
|
||||
|
||||
/**
|
||||
* The barcode reader activity itself. This is loosely based on the CameraPreview
|
||||
* example included in the Android SDK.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public final class CaptureActivity extends Activity implements SurfaceHolder.Callback {
|
||||
|
||||
private static final String TAG = "CaptureActivity";
|
||||
|
||||
private static final int SHARE_ID = Menu.FIRST;
|
||||
|
@ -92,23 +94,31 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
|||
NONE
|
||||
}
|
||||
|
||||
public CaptureActivityHandler mHandler;
|
||||
public CaptureActivityHandler handler;
|
||||
|
||||
private ViewfinderView mViewfinderView;
|
||||
private View mStatusView;
|
||||
private View mResultView;
|
||||
private MediaPlayer mMediaPlayer;
|
||||
private Result mLastResult;
|
||||
private boolean mHasSurface;
|
||||
private boolean mPlayBeep;
|
||||
private boolean mVibrate;
|
||||
private boolean mCopyToClipboard;
|
||||
private Source mSource;
|
||||
private String mSourceUrl;
|
||||
private String mDecodeMode;
|
||||
private String mVersionName;
|
||||
private ViewfinderView viewfinderView;
|
||||
private View statusView;
|
||||
private View resultView;
|
||||
private MediaPlayer mediaPlayer;
|
||||
private Result lastResult;
|
||||
private boolean hasSurface;
|
||||
private boolean playBeep;
|
||||
private boolean vibrate;
|
||||
private boolean copyToClipboard;
|
||||
private Source source;
|
||||
private String sourceUrl;
|
||||
private String decodeMode;
|
||||
private String versionName;
|
||||
|
||||
private final OnCompletionListener beepListener = new BeepListener();
|
||||
|
||||
private final OnCompletionListener mBeepListener = 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
|
||||
public void onCreate(Bundle icicle) {
|
||||
|
@ -120,12 +130,12 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
|||
setContentView(R.layout.capture);
|
||||
|
||||
CameraManager.init(getApplication());
|
||||
mViewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
|
||||
mResultView = findViewById(R.id.result_view);
|
||||
mStatusView = findViewById(R.id.status_view);
|
||||
mHandler = null;
|
||||
mLastResult = null;
|
||||
mHasSurface = false;
|
||||
viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
|
||||
resultView = findViewById(R.id.result_view);
|
||||
statusView = findViewById(R.id.status_view);
|
||||
handler = null;
|
||||
lastResult = null;
|
||||
hasSurface = false;
|
||||
|
||||
showHelpOnFirstLaunch();
|
||||
}
|
||||
|
@ -136,7 +146,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
|||
|
||||
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
|
||||
SurfaceHolder surfaceHolder = surfaceView.getHolder();
|
||||
if (mHasSurface) {
|
||||
if (hasSurface) {
|
||||
// The activity was paused but not stopped, so the surface still exists. Therefore
|
||||
// surfaceCreated() won't be called, so init the camera here.
|
||||
initCamera(surfaceHolder);
|
||||
|
@ -150,52 +160,52 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
|||
String action = intent == null ? null : intent.getAction();
|
||||
String dataString = intent == null ? null : intent.getDataString();
|
||||
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.
|
||||
mSource = Source.NATIVE_APP_INTENT;
|
||||
mDecodeMode = intent.getStringExtra(Intents.Scan.MODE);
|
||||
source = Source.NATIVE_APP_INTENT;
|
||||
decodeMode = intent.getStringExtra(Intents.Scan.MODE);
|
||||
resetStatusView();
|
||||
} else if (dataString != null && dataString.contains(PRODUCT_SEARCH_URL_PREFIX) &&
|
||||
dataString.contains(PRODUCT_SEARCH_URL_SUFFIX)) {
|
||||
// Scan only products and send the result to mobile Product Search.
|
||||
mSource = Source.PRODUCT_SEARCH_LINK;
|
||||
mSourceUrl = dataString;
|
||||
mDecodeMode = Intents.Scan.PRODUCT_MODE;
|
||||
source = Source.PRODUCT_SEARCH_LINK;
|
||||
sourceUrl = dataString;
|
||||
decodeMode = Intents.Scan.PRODUCT_MODE;
|
||||
resetStatusView();
|
||||
} else if (dataString != null && dataString.equals(ZXING_URL)) {
|
||||
// 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.
|
||||
mSource = Source.ZXING_LINK;
|
||||
mSourceUrl = dataString;
|
||||
mDecodeMode = null;
|
||||
source = Source.ZXING_LINK;
|
||||
sourceUrl = dataString;
|
||||
decodeMode = null;
|
||||
resetStatusView();
|
||||
} else {
|
||||
// Scan all formats and handle the results ourselves (launched from Home).
|
||||
mSource = Source.NONE;
|
||||
mDecodeMode = null;
|
||||
source = Source.NONE;
|
||||
decodeMode = null;
|
||||
resetStatusView();
|
||||
}
|
||||
} else {
|
||||
mSource = Source.NONE;
|
||||
mDecodeMode = null;
|
||||
if (mLastResult == null) {
|
||||
source = Source.NONE;
|
||||
decodeMode = null;
|
||||
if (lastResult == null) {
|
||||
resetStatusView();
|
||||
}
|
||||
}
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
mPlayBeep = prefs.getBoolean(PreferencesActivity.KEY_PLAY_BEEP, true);
|
||||
mVibrate = prefs.getBoolean(PreferencesActivity.KEY_VIBRATE, false);
|
||||
mCopyToClipboard = prefs.getBoolean(PreferencesActivity.KEY_COPY_TO_CLIPBOARD, true);
|
||||
playBeep = prefs.getBoolean(PreferencesActivity.KEY_PLAY_BEEP, true);
|
||||
vibrate = prefs.getBoolean(PreferencesActivity.KEY_VIBRATE, false);
|
||||
copyToClipboard = prefs.getBoolean(PreferencesActivity.KEY_COPY_TO_CLIPBOARD, true);
|
||||
initBeepSound();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (mHandler != null) {
|
||||
mHandler.quitSynchronously();
|
||||
mHandler = null;
|
||||
if (handler != null) {
|
||||
handler.quitSynchronously();
|
||||
handler = null;
|
||||
}
|
||||
CameraManager.get().closeDriver();
|
||||
}
|
||||
|
@ -203,13 +213,13 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
|||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
if (mSource == Source.NATIVE_APP_INTENT) {
|
||||
if (source == Source.NATIVE_APP_INTENT) {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
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();
|
||||
mHandler.sendEmptyMessage(R.id.restart_preview);
|
||||
handler.sendEmptyMessage(R.id.restart_preview);
|
||||
return true;
|
||||
}
|
||||
} else if (keyCode == KeyEvent.KEYCODE_FOCUS || keyCode == KeyEvent.KEYCODE_CAMERA) {
|
||||
|
@ -236,7 +246,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
|||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
menu.findItem(SHARE_ID).setVisible(mLastResult == null);
|
||||
menu.findItem(SHARE_ID).setVisible(lastResult == null);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -263,10 +273,10 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
|||
}
|
||||
case ABOUT_ID:
|
||||
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.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.show();
|
||||
break;
|
||||
|
@ -280,22 +290,15 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
|||
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) {
|
||||
if (!mHasSurface) {
|
||||
mHasSurface = true;
|
||||
if (!hasSurface) {
|
||||
hasSurface = true;
|
||||
initCamera(holder);
|
||||
}
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
mHasSurface = false;
|
||||
hasSurface = false;
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
public void handleDecode(Result rawResult, Bitmap barcode) {
|
||||
mLastResult = rawResult;
|
||||
lastResult = rawResult;
|
||||
playBeepSoundAndVibrate();
|
||||
drawResultPoints(barcode, rawResult);
|
||||
|
||||
switch (mSource) {
|
||||
switch (source) {
|
||||
case NATIVE_APP_INTENT:
|
||||
case PRODUCT_SEARCH_LINK:
|
||||
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.
|
||||
private void handleDecodeInternally(Result rawResult, Bitmap barcode) {
|
||||
mStatusView.setVisibility(View.GONE);
|
||||
mViewfinderView.setVisibility(View.GONE);
|
||||
mResultView.setVisibility(View.VISIBLE);
|
||||
statusView.setVisibility(View.GONE);
|
||||
viewfinderView.setVisibility(View.GONE);
|
||||
resultView.setVisibility(View.VISIBLE);
|
||||
|
||||
ImageView barcodeImageView = (ImageView) findViewById(R.id.barcode_image_view);
|
||||
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);
|
||||
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.
|
||||
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
|
||||
// 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.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);
|
||||
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
|
||||
// the deprecated intent is retired.
|
||||
Intent intent = new Intent(getIntent().getAction());
|
||||
intent.putExtra(Intents.Scan.RESULT, rawResult.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;
|
||||
mHandler.sendMessageDelayed(message, INTENT_RESULT_DURATION);
|
||||
} else if (mSource == Source.PRODUCT_SEARCH_LINK) {
|
||||
handler.sendMessageDelayed(message, INTENT_RESULT_DURATION);
|
||||
} else if (source == Source.PRODUCT_SEARCH_LINK) {
|
||||
// Reformulate the URL which triggered us into a query, so that the request goes to the same
|
||||
// TLD as the scan URL.
|
||||
Message message = Message.obtain(mHandler, R.id.launch_product_query);
|
||||
int end = mSourceUrl.lastIndexOf("/scan");
|
||||
message.obj = mSourceUrl.substring(0, end) + "?q=" +
|
||||
Message message = Message.obtain(handler, R.id.launch_product_query);
|
||||
int end = sourceUrl.lastIndexOf("/scan");
|
||||
message.obj = sourceUrl.substring(0, end) + "?q=" +
|
||||
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;
|
||||
// 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.
|
||||
this.mVersionName = info.versionName;
|
||||
this.versionName = info.versionName;
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
int lastVersion = prefs.getInt(PreferencesActivity.KEY_HELP_VERSION_SHOWN, 0);
|
||||
if (currentVersion > lastVersion) {
|
||||
|
@ -474,29 +477,29 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
|||
* latency possible.
|
||||
*/
|
||||
private void initBeepSound() {
|
||||
if (mPlayBeep && mMediaPlayer == null) {
|
||||
mMediaPlayer = new MediaPlayer();
|
||||
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_SYSTEM);
|
||||
mMediaPlayer.setOnCompletionListener(mBeepListener);
|
||||
if (playBeep && mediaPlayer == null) {
|
||||
mediaPlayer = new MediaPlayer();
|
||||
mediaPlayer.setAudioStreamType(AudioManager.STREAM_SYSTEM);
|
||||
mediaPlayer.setOnCompletionListener(beepListener);
|
||||
|
||||
AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
|
||||
try {
|
||||
mMediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(),
|
||||
mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(),
|
||||
file.getLength());
|
||||
file.close();
|
||||
mMediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
|
||||
mMediaPlayer.prepare();
|
||||
mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
|
||||
mediaPlayer.prepare();
|
||||
} catch (IOException e) {
|
||||
mMediaPlayer = null;
|
||||
mediaPlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void playBeepSoundAndVibrate() {
|
||||
if (mPlayBeep && mMediaPlayer != null) {
|
||||
mMediaPlayer.start();
|
||||
if (playBeep && mediaPlayer != null) {
|
||||
mediaPlayer.start();
|
||||
}
|
||||
if (mVibrate) {
|
||||
if (vibrate) {
|
||||
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
||||
vibrator.vibrate(VIBRATE_DURATION);
|
||||
}
|
||||
|
@ -509,27 +512,27 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
|||
Log.w(TAG, ioe);
|
||||
return;
|
||||
}
|
||||
if (mHandler == null) {
|
||||
boolean beginScanning = mLastResult == null;
|
||||
mHandler = new CaptureActivityHandler(this, mDecodeMode, beginScanning);
|
||||
if (handler == null) {
|
||||
boolean beginScanning = lastResult == null;
|
||||
handler = new CaptureActivityHandler(this, decodeMode, beginScanning);
|
||||
}
|
||||
}
|
||||
|
||||
private void resetStatusView() {
|
||||
mResultView.setVisibility(View.GONE);
|
||||
mStatusView.setVisibility(View.VISIBLE);
|
||||
mStatusView.setBackgroundColor(getResources().getColor(R.color.status_view));
|
||||
mViewfinderView.setVisibility(View.VISIBLE);
|
||||
resultView.setVisibility(View.GONE);
|
||||
statusView.setVisibility(View.VISIBLE);
|
||||
statusView.setBackgroundColor(getResources().getColor(R.color.status_view));
|
||||
viewfinderView.setVisibility(View.VISIBLE);
|
||||
|
||||
TextView textView = (TextView) findViewById(R.id.status_text_view);
|
||||
textView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
|
||||
textView.setTextSize(14.0f);
|
||||
textView.setText(R.string.msg_default_status);
|
||||
mLastResult = null;
|
||||
lastResult = null;
|
||||
}
|
||||
|
||||
public void drawViewfinder() {
|
||||
mViewfinderView.drawViewfinder();
|
||||
viewfinderView.drawViewfinder();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -540,5 +543,4 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
|
|||
mediaPlayer.seekTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package com.google.zxing.client.android;
|
||||
|
||||
import com.google.zxing.Result;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
|
@ -23,16 +25,16 @@ import android.net.Uri;
|
|||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import com.google.zxing.Result;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
private final CaptureActivity mActivity;
|
||||
private final DecodeThread mDecodeThread;
|
||||
private State mState;
|
||||
private final CaptureActivity activity;
|
||||
private final DecodeThread decodeThread;
|
||||
private State state;
|
||||
|
||||
private enum State {
|
||||
PREVIEW,
|
||||
|
@ -42,10 +44,10 @@ public final class CaptureActivityHandler extends Handler {
|
|||
|
||||
CaptureActivityHandler(CaptureActivity activity, String decodeMode,
|
||||
boolean beginScanning) {
|
||||
mActivity = activity;
|
||||
mDecodeThread = new DecodeThread(activity, decodeMode);
|
||||
mDecodeThread.start();
|
||||
mState = State.SUCCESS;
|
||||
this.activity = activity;
|
||||
decodeThread = new DecodeThread(activity, decodeMode);
|
||||
decodeThread.start();
|
||||
state = State.SUCCESS;
|
||||
|
||||
// Start ourselves capturing previews and decoding.
|
||||
CameraManager.get().startPreview();
|
||||
|
@ -60,7 +62,7 @@ public final class CaptureActivityHandler extends Handler {
|
|||
case R.id.auto_focus:
|
||||
// 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.
|
||||
if (mState == State.PREVIEW) {
|
||||
if (state == State.PREVIEW) {
|
||||
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
|
||||
}
|
||||
break;
|
||||
|
@ -68,34 +70,34 @@ public final class CaptureActivityHandler extends Handler {
|
|||
restartPreviewAndDecode();
|
||||
break;
|
||||
case R.id.decode_succeeded:
|
||||
mState = State.SUCCESS;
|
||||
state = State.SUCCESS;
|
||||
Bundle bundle = message.getData();
|
||||
Bitmap barcode = bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
|
||||
mActivity.handleDecode((Result) message.obj, barcode);
|
||||
activity.handleDecode((Result) message.obj, barcode);
|
||||
break;
|
||||
case R.id.decode_failed:
|
||||
// We're decoding as fast as possible, so when one decode fails, start another.
|
||||
mState = State.PREVIEW;
|
||||
CameraManager.get().requestPreviewFrame(mDecodeThread.mHandler, R.id.decode);
|
||||
state = State.PREVIEW;
|
||||
CameraManager.get().requestPreviewFrame(decodeThread.handler, R.id.decode);
|
||||
break;
|
||||
case R.id.return_scan_result:
|
||||
mActivity.setResult(Activity.RESULT_OK, (Intent) message.obj);
|
||||
mActivity.finish();
|
||||
activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
|
||||
activity.finish();
|
||||
break;
|
||||
case R.id.launch_product_query:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public void quitSynchronously() {
|
||||
mState = State.DONE;
|
||||
state = State.DONE;
|
||||
CameraManager.get().stopPreview();
|
||||
Message quit = Message.obtain(mDecodeThread.mHandler, R.id.quit);
|
||||
Message quit = Message.obtain(decodeThread.handler, R.id.quit);
|
||||
quit.sendToTarget();
|
||||
try {
|
||||
mDecodeThread.join();
|
||||
decodeThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
|
@ -105,12 +107,11 @@ public final class CaptureActivityHandler extends Handler {
|
|||
}
|
||||
|
||||
private void restartPreviewAndDecode() {
|
||||
if (mState == State.SUCCESS) {
|
||||
mState = State.PREVIEW;
|
||||
CameraManager.get().requestPreviewFrame(mDecodeThread.mHandler, R.id.decode);
|
||||
if (state == State.SUCCESS) {
|
||||
state = State.PREVIEW;
|
||||
CameraManager.get().requestPreviewFrame(decodeThread.handler, R.id.decode);
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
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
|
||||
* phone numbers and addresses.
|
||||
*/
|
||||
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 = {
|
||||
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 android.content.SharedPreferences;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
@ -38,19 +37,20 @@ import java.util.Vector;
|
|||
|
||||
/**
|
||||
* This thread does all the heavy lifting of decoding the images.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
final class DecodeThread extends Thread {
|
||||
|
||||
public static final String BARCODE_BITMAP = "barcode_bitmap";
|
||||
private static final String TAG = "DecodeThread";
|
||||
|
||||
public Handler mHandler;
|
||||
private final CaptureActivity mActivity;
|
||||
private final MultiFormatReader mMultiFormatReader;
|
||||
public Handler handler;
|
||||
private final CaptureActivity activity;
|
||||
private final MultiFormatReader multiFormatReader;
|
||||
|
||||
DecodeThread(CaptureActivity activity, String mode) {
|
||||
mActivity = activity;
|
||||
mMultiFormatReader = new MultiFormatReader();
|
||||
this.activity = activity;
|
||||
multiFormatReader = new MultiFormatReader();
|
||||
|
||||
// The prefs can't change while the thread is running, so pick them up once here.
|
||||
if (mode == null || mode.length() == 0) {
|
||||
|
@ -80,7 +80,7 @@ final class DecodeThread extends Thread {
|
|||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
mHandler = new Handler() {
|
||||
handler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
switch (message.what) {
|
||||
|
@ -104,7 +104,7 @@ final class DecodeThread extends Thread {
|
|||
vector.addElement(BarcodeFormat.EAN_13);
|
||||
vector.addElement(BarcodeFormat.EAN_8);
|
||||
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.ITF);
|
||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
||||
mMultiFormatReader.setHints(hints);
|
||||
multiFormatReader.setHints(hints);
|
||||
}
|
||||
|
||||
private void setDecodeQRMode() {
|
||||
|
@ -129,7 +129,7 @@ final class DecodeThread extends Thread {
|
|||
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>(1);
|
||||
vector.addElement(BarcodeFormat.QR_CODE);
|
||||
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.QR_CODE);
|
||||
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();
|
||||
boolean success;
|
||||
Result rawResult = null;
|
||||
Rect rect = CameraManager.get().getFramingRect();
|
||||
YUVLuminanceSource source = new YUVLuminanceSource(data, width, height, rect.left, rect.top,
|
||||
rect.width(), rect.height());
|
||||
BaseLuminanceSource source = CameraManager.get().buildLuminanceSource(data, width, height);
|
||||
BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
|
||||
try {
|
||||
rawResult = mMultiFormatReader.decodeWithState(bitmap);
|
||||
rawResult = multiFormatReader.decodeWithState(bitmap);
|
||||
success = true;
|
||||
} catch (ReaderException e) {
|
||||
success = false;
|
||||
|
@ -177,15 +175,14 @@ final class DecodeThread extends Thread {
|
|||
|
||||
if (success) {
|
||||
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.putParcelable(BARCODE_BITMAP, source.renderToBitmap());
|
||||
bundle.putParcelable(BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
|
||||
message.setData(bundle);
|
||||
message.sendToTarget();
|
||||
} else {
|
||||
Message message = Message.obtain(mActivity.mHandler, R.id.decode_failed);
|
||||
Message message = Message.obtain(activity.handler, R.id.decode_failed);
|
||||
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
|
||||
* another person can scan it with their device.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public final class EncodeActivity extends Activity {
|
||||
private QRCodeEncoder qrCodeEncoder;
|
||||
private ProgressDialog progressDialog;
|
||||
private boolean firstLayout;
|
||||
|
||||
private QRCodeEncoder mQRCodeEncoder;
|
||||
private ProgressDialog mProgressDialog;
|
||||
private boolean mFirstLayout;
|
||||
/**
|
||||
* This needs to be delayed until after the first layout so that the view dimensions will be
|
||||
* 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
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
Intent intent = getIntent();
|
||||
if (intent != null && (intent.getAction().equals(Intents.Encode.ACTION) ||
|
||||
intent.getAction().equals(Intents.Encode.DEPRECATED_ACTION))) {
|
||||
if (intent != null && (intent.getAction().equals(Intents.Encode.ACTION))) {
|
||||
setContentView(R.layout.encode);
|
||||
} else {
|
||||
finish();
|
||||
|
@ -60,81 +122,18 @@ public final class EncodeActivity extends Activity {
|
|||
super.onResume();
|
||||
|
||||
View layout = findViewById(R.id.encode_view);
|
||||
layout.getViewTreeObserver().addOnGlobalLayoutListener(mLayoutListener);
|
||||
mFirstLayout = true;
|
||||
layout.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
|
||||
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) {
|
||||
if (mProgressDialog != null) {
|
||||
mProgressDialog.dismiss();
|
||||
mProgressDialog = null;
|
||||
if (progressDialog != null) {
|
||||
progressDialog.dismiss();
|
||||
progressDialog = null;
|
||||
}
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(message);
|
||||
builder.setPositiveButton(R.string.button_ok, mClickListener);
|
||||
builder.setPositiveButton(R.string.button_ok, clickListener);
|
||||
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;
|
||||
|
||||
/**
|
||||
* An HTML-based help screen with Back and Done buttons at the bottom.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public final class HelpActivity extends Activity {
|
||||
|
||||
private static final String DEFAULT_URL = "file:///android_asset/html/index.html";
|
||||
|
||||
private WebView mWebView;
|
||||
private Button mBackButton;
|
||||
private WebView webView;
|
||||
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
|
||||
protected void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
setContentView(R.layout.help);
|
||||
|
||||
mWebView = (WebView)findViewById(R.id.help_contents);
|
||||
mWebView.setWebViewClient(new HelpClient());
|
||||
webView = (WebView)findViewById(R.id.help_contents);
|
||||
webView.setWebViewClient(new HelpClient());
|
||||
if (icicle != null) {
|
||||
mWebView.restoreState(icicle);
|
||||
webView.restoreState(icicle);
|
||||
} else {
|
||||
mWebView.loadUrl(DEFAULT_URL);
|
||||
webView.loadUrl(DEFAULT_URL);
|
||||
}
|
||||
|
||||
mBackButton = (Button)findViewById(R.id.back_button);
|
||||
mBackButton.setOnClickListener(mBackListener);
|
||||
backButton = (Button)findViewById(R.id.back_button);
|
||||
backButton.setOnClickListener(backListener);
|
||||
|
||||
Button doneButton = (Button)findViewById(R.id.done_button);
|
||||
doneButton.setOnClickListener(mDoneListener);
|
||||
doneButton.setOnClickListener(doneListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,40 +74,26 @@ public final class HelpActivity extends Activity {
|
|||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle state) {
|
||||
mWebView.saveState(state);
|
||||
webView.saveState(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
if (mWebView.canGoBack()) {
|
||||
mWebView.goBack();
|
||||
if (webView.canGoBack()) {
|
||||
webView.goBack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
setTitle(view.getTitle());
|
||||
mBackButton.setEnabled(view.canGoBack());
|
||||
backButton.setEnabled(view.canGoBack());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,8 +16,13 @@
|
|||
|
||||
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 {
|
||||
|
||||
private Intents() {
|
||||
}
|
||||
|
||||
|
@ -28,9 +33,6 @@ public final class Intents {
|
|||
*/
|
||||
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
|
||||
* 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";
|
||||
|
||||
// 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
|
||||
* 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";
|
||||
|
||||
// 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.
|
||||
*/
|
||||
|
@ -139,5 +135,4 @@ public final class Intents {
|
|||
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.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class LocaleManager {
|
||||
|
||||
private static final String DEFAULT_TLD = "com";
|
||||
private static final Map<Locale,String> GOOGLE_COUNTRY_TLD;
|
||||
static {
|
||||
|
@ -93,5 +94,4 @@ public final class LocaleManager {
|
|||
}
|
||||
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.PreferenceScreen;
|
||||
|
||||
/**
|
||||
* The main settings activity.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public final class PreferencesActivity extends PreferenceActivity
|
||||
implements OnSharedPreferenceChangeListener {
|
||||
|
||||
|
@ -36,8 +41,8 @@ public final class PreferencesActivity extends PreferenceActivity
|
|||
|
||||
static final String KEY_HELP_VERSION_SHOWN = "preferences_help_version_shown";
|
||||
|
||||
CheckBoxPreference mDecode1D;
|
||||
CheckBoxPreference mDecodeQR;
|
||||
CheckBoxPreference decode1D;
|
||||
CheckBoxPreference decodeQR;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle) {
|
||||
|
@ -46,19 +51,18 @@ public final class PreferencesActivity extends PreferenceActivity
|
|||
|
||||
PreferenceScreen preferences = getPreferenceScreen();
|
||||
preferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
|
||||
mDecode1D = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_1D);
|
||||
mDecodeQR = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_QR);
|
||||
decode1D = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_1D);
|
||||
decodeQR = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_QR);
|
||||
}
|
||||
|
||||
// Prevent the user from turning off both decode options
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (key.equals(KEY_DECODE_1D)) {
|
||||
mDecodeQR.setEnabled(mDecode1D.isChecked());
|
||||
mDecodeQR.setChecked(true);
|
||||
decodeQR.setEnabled(decode1D.isChecked());
|
||||
decodeQR.setChecked(true);
|
||||
} else if (key.equals(KEY_DECODE_QR)) {
|
||||
mDecode1D.setEnabled(mDecodeQR.isChecked());
|
||||
mDecode1D.setChecked(true);
|
||||
decode1D.setEnabled(decodeQR.isChecked());
|
||||
decode1D.setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,11 @@
|
|||
|
||||
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.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
|
@ -23,48 +28,49 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.provider.Contacts;
|
||||
import android.util.Log;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.ByteMatrix;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
private final Activity mActivity;
|
||||
private String mContents;
|
||||
private String mDisplayContents;
|
||||
private String mTitle;
|
||||
private BarcodeFormat mFormat;
|
||||
private final Activity activity;
|
||||
private String contents;
|
||||
private String displayContents;
|
||||
private String title;
|
||||
private BarcodeFormat format;
|
||||
|
||||
public QRCodeEncoder(Activity activity, Intent intent) {
|
||||
mActivity = activity;
|
||||
this.activity = activity;
|
||||
if (!encodeContents(intent)) {
|
||||
throw new IllegalArgumentException("No valid data to encode.");
|
||||
}
|
||||
}
|
||||
|
||||
public void requestBarcode(Handler handler, int pixelResolution) {
|
||||
Thread encodeThread = new EncodeThread(mContents, handler, pixelResolution,
|
||||
mFormat);
|
||||
Thread encodeThread = new EncodeThread(contents, handler, pixelResolution,
|
||||
format);
|
||||
encodeThread.start();
|
||||
}
|
||||
|
||||
public String getContents() {
|
||||
return mContents;
|
||||
return contents;
|
||||
}
|
||||
|
||||
public String getDisplayContents() {
|
||||
return mDisplayContents;
|
||||
return displayContents;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return mFormat.toString();
|
||||
return format.toString();
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return false;
|
||||
}
|
||||
mFormat = BarcodeFormat.QR_CODE;
|
||||
this.format = BarcodeFormat.QR_CODE;
|
||||
encodeQRCodeContents(intent, type);
|
||||
} else {
|
||||
String data = intent.getStringExtra(Intents.Encode.DATA);
|
||||
if (data != null && data.length() != 0) {
|
||||
mContents = data;
|
||||
mDisplayContents = data;
|
||||
mTitle = mActivity.getString(R.string.contents_text);
|
||||
contents = data;
|
||||
displayContents = data;
|
||||
title = activity.getString(R.string.contents_text);
|
||||
if (format.equals(Contents.Format.CODE_128))
|
||||
mFormat = BarcodeFormat.CODE_128;
|
||||
this.format = BarcodeFormat.CODE_128;
|
||||
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))
|
||||
mFormat = BarcodeFormat.EAN_8;
|
||||
this.format = BarcodeFormat.EAN_8;
|
||||
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))
|
||||
mFormat = BarcodeFormat.UPC_A;
|
||||
this.format = BarcodeFormat.UPC_A;
|
||||
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) {
|
||||
if (type.equals(Contents.Type.TEXT)) {
|
||||
String data = intent.getStringExtra(Intents.Encode.DATA);
|
||||
if (data != null && data.length() > 0) {
|
||||
mContents = data;
|
||||
mDisplayContents = data;
|
||||
mTitle = mActivity.getString(R.string.contents_text);
|
||||
contents = data;
|
||||
displayContents = data;
|
||||
title = activity.getString(R.string.contents_text);
|
||||
}
|
||||
} else if (type.equals(Contents.Type.EMAIL)) {
|
||||
String data = intent.getStringExtra(Intents.Encode.DATA);
|
||||
if (data != null && data.length() > 0) {
|
||||
mContents = "mailto:" + data;
|
||||
mDisplayContents = data;
|
||||
mTitle = mActivity.getString(R.string.contents_email);
|
||||
contents = "mailto:" + data;
|
||||
displayContents = data;
|
||||
title = activity.getString(R.string.contents_email);
|
||||
}
|
||||
} else if (type.equals(Contents.Type.PHONE)) {
|
||||
String data = intent.getStringExtra(Intents.Encode.DATA);
|
||||
if (data != null && data.length() > 0) {
|
||||
mContents = "tel:" + data;
|
||||
mDisplayContents = PhoneNumberUtils.formatNumber(data);
|
||||
mTitle = mActivity.getString(R.string.contents_phone);
|
||||
contents = "tel:" + data;
|
||||
displayContents = PhoneNumberUtils.formatNumber(data);
|
||||
title = activity.getString(R.string.contents_phone);
|
||||
}
|
||||
} else if (type.equals(Contents.Type.SMS)) {
|
||||
String data = intent.getStringExtra(Intents.Encode.DATA);
|
||||
if (data != null && data.length() > 0) {
|
||||
mContents = "sms:" + data;
|
||||
mDisplayContents = PhoneNumberUtils.formatNumber(data);
|
||||
mTitle = mActivity.getString(R.string.contents_sms);
|
||||
contents = "sms:" + data;
|
||||
displayContents = PhoneNumberUtils.formatNumber(data);
|
||||
title = activity.getString(R.string.contents_sms);
|
||||
}
|
||||
} else if (type.equals(Contents.Type.CONTACT)) {
|
||||
Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
|
||||
|
@ -169,12 +175,12 @@ public final class QRCodeEncoder {
|
|||
// Make sure we've encoded at least one field.
|
||||
if (newDisplayContents.length() > 0) {
|
||||
newContents.append(';');
|
||||
mContents = newContents.toString();
|
||||
mDisplayContents = newDisplayContents.toString();
|
||||
mTitle = mActivity.getString(R.string.contents_contact);
|
||||
contents = newContents.toString();
|
||||
displayContents = newDisplayContents.toString();
|
||||
title = activity.getString(R.string.contents_contact);
|
||||
} else {
|
||||
mContents = null;
|
||||
mDisplayContents = null;
|
||||
contents = null;
|
||||
displayContents = null;
|
||||
}
|
||||
}
|
||||
} else if (type.equals(Contents.Type.LOCATION)) {
|
||||
|
@ -184,36 +190,35 @@ public final class QRCodeEncoder {
|
|||
float latitude = bundle.getFloat("LAT", Float.MAX_VALUE);
|
||||
float longitude = bundle.getFloat("LONG", Float.MAX_VALUE);
|
||||
if (latitude != Float.MAX_VALUE && longitude != Float.MAX_VALUE) {
|
||||
mContents = "geo:" + latitude + ',' + longitude;
|
||||
mDisplayContents = latitude + "," + longitude;
|
||||
mTitle = mActivity.getString(R.string.contents_location);
|
||||
contents = "geo:" + latitude + ',' + longitude;
|
||||
displayContents = latitude + "," + longitude;
|
||||
title = activity.getString(R.string.contents_location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class EncodeThread extends Thread {
|
||||
|
||||
private static final String TAG = "EncodeThread";
|
||||
|
||||
private final String mContents;
|
||||
private final Handler mHandler;
|
||||
private final int mPixelResolution;
|
||||
private final BarcodeFormat mFormat;
|
||||
private final String contents;
|
||||
private final Handler handler;
|
||||
private final int pixelResolution;
|
||||
private final BarcodeFormat format;
|
||||
|
||||
EncodeThread(String contents, Handler handler, int pixelResolution,
|
||||
BarcodeFormat format) {
|
||||
mContents = contents;
|
||||
mHandler = handler;
|
||||
mPixelResolution = pixelResolution;
|
||||
mFormat = format;
|
||||
this.contents = contents;
|
||||
this.handler = handler;
|
||||
this.pixelResolution = pixelResolution;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ByteMatrix result = new MultiFormatWriter().encode(mContents,
|
||||
mFormat, mPixelResolution, mPixelResolution);
|
||||
ByteMatrix result = new MultiFormatWriter().encode(contents, format,
|
||||
pixelResolution, pixelResolution);
|
||||
int width = result.getWidth();
|
||||
int height = result.getHeight();
|
||||
byte[][] array = result.getArray();
|
||||
|
@ -228,19 +233,18 @@ public final class QRCodeEncoder {
|
|||
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
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.sendToTarget();
|
||||
} catch (WriterException e) {
|
||||
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();
|
||||
} catch (IllegalArgumentException e) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -48,17 +48,53 @@ import java.net.URI;
|
|||
import java.util.ArrayList;
|
||||
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 {
|
||||
|
||||
private static final String TAG = "SearchBookContents";
|
||||
private static final String USER_AGENT = "ZXing (Android)";
|
||||
|
||||
private NetworkThread mNetworkThread;
|
||||
private String mISBN;
|
||||
private EditText mQueryTextView;
|
||||
private Button mQueryButton;
|
||||
private ListView mResultListView;
|
||||
private TextView mHeaderView;
|
||||
private NetworkThread networkThread;
|
||||
private String isbn;
|
||||
private EditText queryTextView;
|
||||
private Button queryButton;
|
||||
private ListView resultListView;
|
||||
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
|
||||
public void onCreate(Bundle icicle) {
|
||||
|
@ -69,39 +105,38 @@ public final class SearchBookContentsActivity extends Activity {
|
|||
CookieManager.getInstance().removeExpiredCookie();
|
||||
|
||||
Intent intent = getIntent();
|
||||
if (intent == null || (!intent.getAction().equals(Intents.SearchBookContents.ACTION) &&
|
||||
!intent.getAction().equals(Intents.SearchBookContents.DEPRECATED_ACTION))) {
|
||||
if (intent == null || (!intent.getAction().equals(Intents.SearchBookContents.ACTION))) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
mISBN = intent.getStringExtra(Intents.SearchBookContents.ISBN);
|
||||
setTitle(getString(R.string.sbc_name) + ": ISBN " + mISBN);
|
||||
isbn = intent.getStringExtra(Intents.SearchBookContents.ISBN);
|
||||
setTitle(getString(R.string.sbc_name) + ": ISBN " + isbn);
|
||||
|
||||
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);
|
||||
if (initialQuery != null && initialQuery.length() > 0) {
|
||||
// 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);
|
||||
mQueryButton.setOnClickListener(mButtonListener);
|
||||
queryButton = (Button) findViewById(R.id.query_button);
|
||||
queryButton.setOnClickListener(buttonListener);
|
||||
|
||||
mResultListView = (ListView) findViewById(R.id.result_list_view);
|
||||
resultListView = (ListView) findViewById(R.id.result_list_view);
|
||||
LayoutInflater factory = LayoutInflater.from(this);
|
||||
mHeaderView = (TextView) factory.inflate(R.layout.search_book_contents_header,
|
||||
mResultListView, false);
|
||||
mResultListView.addHeaderView(mHeaderView);
|
||||
headerView = (TextView) factory.inflate(R.layout.search_book_contents_header,
|
||||
resultListView, false);
|
||||
resultListView.addHeaderView(headerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
mQueryTextView.selectAll();
|
||||
queryTextView.selectAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -110,55 +145,23 @@ public final class SearchBookContentsActivity extends Activity {
|
|||
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() {
|
||||
mNetworkThread = null;
|
||||
mQueryTextView.setEnabled(true);
|
||||
mQueryTextView.selectAll();
|
||||
mQueryButton.setEnabled(true);
|
||||
networkThread = null;
|
||||
queryTextView.setEnabled(true);
|
||||
queryTextView.selectAll();
|
||||
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() {
|
||||
if (mNetworkThread == null) {
|
||||
String query = mQueryTextView.getText().toString();
|
||||
if (networkThread == null) {
|
||||
String query = queryTextView.getText().toString();
|
||||
if (query != null && query.length() > 0) {
|
||||
mNetworkThread = new NetworkThread(mISBN, query, mHandler);
|
||||
mNetworkThread.start();
|
||||
mHeaderView.setText(R.string.msg_sbc_searching_book);
|
||||
mResultListView.setAdapter(null);
|
||||
mQueryTextView.setEnabled(false);
|
||||
mQueryButton.setEnabled(false);
|
||||
networkThread = new NetworkThread(isbn, query, handler);
|
||||
networkThread.start();
|
||||
headerView.setText(R.string.msg_sbc_searching_book);
|
||||
resultListView.setAdapter(null);
|
||||
queryTextView.setEnabled(false);
|
||||
queryButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,26 +171,26 @@ public final class SearchBookContentsActivity extends Activity {
|
|||
private void handleSearchResults(JSONObject json) {
|
||||
try {
|
||||
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) {
|
||||
JSONArray results = json.getJSONArray("search_results");
|
||||
SearchBookContentsResult.setQuery(mQueryTextView.getText().toString());
|
||||
SearchBookContentsResult.setQuery(queryTextView.getText().toString());
|
||||
List<SearchBookContentsResult> items = new ArrayList<SearchBookContentsResult>(count);
|
||||
for (int x = 0; x < count; x++) {
|
||||
items.add(parseResult(results.getJSONObject(x)));
|
||||
}
|
||||
mResultListView.setAdapter(new SearchBookContentsAdapter(this, items));
|
||||
resultListView.setAdapter(new SearchBookContentsAdapter(this, items));
|
||||
} else {
|
||||
String searchable = json.optString("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) {
|
||||
Log.e(TAG, e.toString());
|
||||
mResultListView.setAdapter(null);
|
||||
mHeaderView.setText(R.string.msg_sbc_failed);
|
||||
resultListView.setAdapter(null);
|
||||
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 final String mISBN;
|
||||
private final String mQuery;
|
||||
private final Handler mHandler;
|
||||
private final String isbn;
|
||||
private final String query;
|
||||
private final Handler handler;
|
||||
|
||||
NetworkThread(String isbn, String query, Handler handler) {
|
||||
mISBN = isbn;
|
||||
mQuery = query;
|
||||
mHandler = handler;
|
||||
this.isbn = isbn;
|
||||
this.query = query;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@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
|
||||
// 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.
|
||||
URI uri = new URI("http", null, "www.google.com", -1, "/books", "vid=isbn" + mISBN +
|
||||
"&jscmd=SearchWithinVolume2&q=" + mQuery, null);
|
||||
URI uri = new URI("http", null, "www.google.com", -1, "/books", "vid=isbn" + isbn +
|
||||
"&jscmd=SearchWithinVolume2&q=" + query, null);
|
||||
HttpUriRequest get = new HttpGet(uri);
|
||||
get.setHeader("cookie", getCookie(uri.toString()));
|
||||
client = AndroidHttpClient.newInstance(USER_AGENT);
|
||||
|
@ -255,17 +257,17 @@ public final class SearchBookContentsActivity extends Activity {
|
|||
JSONObject json = new JSONObject(jsonHolder.toString(getEncoding(entity)));
|
||||
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.sendToTarget();
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
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();
|
||||
} finally {
|
||||
if (client != null) {
|
||||
|
@ -316,5 +318,4 @@ public final class SearchBookContentsActivity extends Activity {
|
|||
// return "UTF-8";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,8 +24,12 @@ import android.widget.ArrayAdapter;
|
|||
|
||||
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 SearchBookContentsAdapter(Context context, List<SearchBookContentsResult> 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);
|
||||
return listItem;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,10 +25,14 @@ import android.util.AttributeSet;
|
|||
import android.widget.LinearLayout;
|
||||
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 {
|
||||
|
||||
private TextView mPageNumberView;
|
||||
private TextView mSnippetView;
|
||||
private TextView pageNumberView;
|
||||
private TextView snippetView;
|
||||
|
||||
SearchBookContentsListItem(Context context) {
|
||||
super(context);
|
||||
|
@ -41,12 +45,12 @@ public final class SearchBookContentsListItem extends LinearLayout {
|
|||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mPageNumberView = (TextView) findViewById(R.id.page_number_view);
|
||||
mSnippetView = (TextView) findViewById(R.id.snippet_view);
|
||||
pageNumberView = (TextView) findViewById(R.id.page_number_view);
|
||||
snippetView = (TextView) findViewById(R.id.snippet_view);
|
||||
}
|
||||
|
||||
public void set(SearchBookContentsResult result) {
|
||||
mPageNumberView.setText(result.getPageNumber());
|
||||
pageNumberView.setText(result.getPageNumber());
|
||||
String snippet = result.getSnippet();
|
||||
if (snippet.length() > 0) {
|
||||
if (result.getValidSnippet()) {
|
||||
|
@ -64,14 +68,13 @@ public final class SearchBookContentsListItem extends LinearLayout {
|
|||
styledSnippet.setSpan(boldSpan, pos, pos + queryLength, 0);
|
||||
offset = pos + queryLength;
|
||||
}
|
||||
mSnippetView.setText(styledSnippet);
|
||||
snippetView.setText(styledSnippet);
|
||||
} else {
|
||||
// This may be an error message, so don't try to bold the query terms within it
|
||||
mSnippetView.setText(snippet);
|
||||
snippetView.setText(snippet);
|
||||
}
|
||||
} else {
|
||||
mSnippetView.setText("");
|
||||
snippetView.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,38 +16,41 @@
|
|||
|
||||
package com.google.zxing.client.android;
|
||||
|
||||
/**
|
||||
* The underlying data for a SBC result.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public final class SearchBookContentsResult {
|
||||
private static String query;
|
||||
|
||||
private static String sQuery;
|
||||
|
||||
private final String mPageNumber;
|
||||
private final String mSnippet;
|
||||
private final boolean mValidSnippet;
|
||||
private final String pageNumber;
|
||||
private final String snippet;
|
||||
private final boolean validSnippet;
|
||||
|
||||
public SearchBookContentsResult(String pageNumber, String snippet, boolean validSnippet) {
|
||||
mPageNumber = pageNumber;
|
||||
mSnippet = snippet;
|
||||
mValidSnippet = validSnippet;
|
||||
this.pageNumber = pageNumber;
|
||||
this.snippet = snippet;
|
||||
this.validSnippet = validSnippet;
|
||||
}
|
||||
|
||||
public static void setQuery(String query) {
|
||||
sQuery = query;
|
||||
SearchBookContentsResult.query = query;
|
||||
}
|
||||
|
||||
public String getPageNumber() {
|
||||
return mPageNumber;
|
||||
return pageNumber;
|
||||
}
|
||||
|
||||
public String getSnippet() {
|
||||
return mSnippet;
|
||||
return snippet;
|
||||
}
|
||||
|
||||
public boolean getValidSnippet() {
|
||||
return mValidSnippet;
|
||||
return validSnippet;
|
||||
}
|
||||
|
||||
public static String getQuery() {
|
||||
return sQuery;
|
||||
return query;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,8 +29,13 @@ import android.text.ClipboardManager;
|
|||
import android.view.View;
|
||||
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 {
|
||||
|
||||
private static final int PICK_BOOKMARK = 0;
|
||||
private static final int PICK_CONTACT = 1;
|
||||
|
||||
|
@ -51,43 +56,16 @@ public final class ShareActivity extends Activity {
|
|||
Contacts.PhonesColumns.NUMBER // 1
|
||||
};
|
||||
|
||||
private Button mClipboardButton;
|
||||
private Button clipboardButton;
|
||||
|
||||
@Override
|
||||
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() {
|
||||
private final Button.OnClickListener contactListener = new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
startActivityForResult(new Intent(Intent.ACTION_PICK, Contacts.People.CONTENT_URI),
|
||||
PICK_CONTACT);
|
||||
}
|
||||
};
|
||||
|
||||
private final Button.OnClickListener mBookmarkListener = new Button.OnClickListener() {
|
||||
private final Button.OnClickListener bookmarkListener = new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK);
|
||||
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) {
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||
// 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
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
if (resultCode == RESULT_OK) {
|
||||
|
@ -213,5 +218,4 @@ public final class ShareActivity extends Activity {
|
|||
}
|
||||
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
|
||||
* 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 {
|
||||
|
||||
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
|
||||
private static final long ANIMATION_DELAY = 100L;
|
||||
|
||||
private final Paint mPaint;
|
||||
private final Rect mBox;
|
||||
private Bitmap mResultBitmap;
|
||||
private final int mMaskColor;
|
||||
private final int mResultColor;
|
||||
private final int mFrameColor;
|
||||
private final int mLaserColor;
|
||||
private int mScannerAlpha;
|
||||
private final Paint paint;
|
||||
private final Rect box;
|
||||
private Bitmap resultBitmap;
|
||||
private final int maskColor;
|
||||
private final int resultColor;
|
||||
private final int frameColor;
|
||||
private final int laserColor;
|
||||
private int scannerAlpha;
|
||||
|
||||
// This constructor is used when the class is built from an XML resource.
|
||||
public ViewfinderView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
// Initialize these once for performance rather than calling them every time in onDraw().
|
||||
mPaint = new Paint();
|
||||
mBox = new Rect();
|
||||
paint = new Paint();
|
||||
box = new Rect();
|
||||
Resources resources = getResources();
|
||||
mMaskColor = resources.getColor(R.color.viewfinder_mask);
|
||||
mResultColor = resources.getColor(R.color.result_view);
|
||||
mFrameColor = resources.getColor(R.color.viewfinder_frame);
|
||||
mLaserColor = resources.getColor(R.color.viewfinder_laser);
|
||||
mScannerAlpha = 0;
|
||||
maskColor = resources.getColor(R.color.viewfinder_mask);
|
||||
resultColor = resources.getColor(R.color.result_view);
|
||||
frameColor = resources.getColor(R.color.viewfinder_frame);
|
||||
laserColor = resources.getColor(R.color.viewfinder_laser);
|
||||
scannerAlpha = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,48 +66,48 @@ public final class ViewfinderView extends View {
|
|||
int height = canvas.getHeight();
|
||||
|
||||
// Draw the exterior (i.e. outside the framing rect) darkened
|
||||
mPaint.setColor(mResultBitmap != null ? mResultColor : mMaskColor);
|
||||
mBox.set(0, 0, width, frame.top);
|
||||
canvas.drawRect(mBox, mPaint);
|
||||
mBox.set(0, frame.top, frame.left, frame.bottom + 1);
|
||||
canvas.drawRect(mBox, mPaint);
|
||||
mBox.set(frame.right + 1, frame.top, width, frame.bottom + 1);
|
||||
canvas.drawRect(mBox, mPaint);
|
||||
mBox.set(0, frame.bottom + 1, width, height);
|
||||
canvas.drawRect(mBox, mPaint);
|
||||
paint.setColor(resultBitmap != null ? resultColor : maskColor);
|
||||
box.set(0, 0, width, frame.top);
|
||||
canvas.drawRect(box, paint);
|
||||
box.set(0, frame.top, frame.left, frame.bottom + 1);
|
||||
canvas.drawRect(box, paint);
|
||||
box.set(frame.right + 1, frame.top, width, frame.bottom + 1);
|
||||
canvas.drawRect(box, paint);
|
||||
box.set(0, frame.bottom + 1, width, height);
|
||||
canvas.drawRect(box, paint);
|
||||
|
||||
if (mResultBitmap != null) {
|
||||
if (resultBitmap != null) {
|
||||
// Draw the opaque result bitmap over the scanning rectangle
|
||||
mPaint.setAlpha(255);
|
||||
canvas.drawBitmap(mResultBitmap, frame.left, frame.top, mPaint);
|
||||
paint.setAlpha(255);
|
||||
canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
|
||||
} else {
|
||||
// Draw a two pixel solid black border inside the framing rect
|
||||
mPaint.setColor(mFrameColor);
|
||||
mBox.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
|
||||
canvas.drawRect(mBox, mPaint);
|
||||
mBox.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
|
||||
canvas.drawRect(mBox, mPaint);
|
||||
mBox.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
|
||||
canvas.drawRect(mBox, mPaint);
|
||||
mBox.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
|
||||
canvas.drawRect(mBox, mPaint);
|
||||
paint.setColor(frameColor);
|
||||
box.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
|
||||
canvas.drawRect(box, paint);
|
||||
box.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
|
||||
canvas.drawRect(box, paint);
|
||||
box.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
|
||||
canvas.drawRect(box, paint);
|
||||
box.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
|
||||
canvas.drawRect(box, paint);
|
||||
|
||||
// Draw a red "laser scanner" line through the middle to show decoding is active
|
||||
mPaint.setColor(mLaserColor);
|
||||
mPaint.setAlpha(SCANNER_ALPHA[mScannerAlpha]);
|
||||
mScannerAlpha = (mScannerAlpha + 1) % SCANNER_ALPHA.length;
|
||||
paint.setColor(laserColor);
|
||||
paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
|
||||
scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
|
||||
int middle = frame.height() / 2 + frame.top;
|
||||
mBox.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
|
||||
canvas.drawRect(mBox, mPaint);
|
||||
box.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
|
||||
canvas.drawRect(box, paint);
|
||||
|
||||
// Request another update at the animation interval, but only repaint the laser line,
|
||||
// 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() {
|
||||
mResultBitmap = null;
|
||||
resultBitmap = null;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
|
@ -116,8 +117,7 @@ public final class ViewfinderView extends View {
|
|||
* @param barcode An image of the decoded barcode.
|
||||
*/
|
||||
public void drawResultBitmap(Bitmap barcode) {
|
||||
mResultBitmap = barcode;
|
||||
resultBitmap = barcode;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,34 +16,39 @@
|
|||
|
||||
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.result.AddressBookParsedResult;
|
||||
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.ParsePosition;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Handles address book entries.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public final class AddressBookResultHandler extends ResultHandler {
|
||||
|
||||
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
|
||||
|
||||
private final boolean[] mFields;
|
||||
private int mButtonCount;
|
||||
private final boolean[] fields;
|
||||
private int buttonCount;
|
||||
|
||||
// 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.
|
||||
private int mapIndexToAction(int index) {
|
||||
if (index < mButtonCount) {
|
||||
if (index < buttonCount) {
|
||||
int count = -1;
|
||||
for (int x = 0; x < MAX_BUTTON_COUNT; x++) {
|
||||
if (mFields[x]) {
|
||||
if (fields[x]) {
|
||||
count++;
|
||||
}
|
||||
if (count == index) {
|
||||
|
@ -64,23 +69,23 @@ public final class AddressBookResultHandler extends ResultHandler {
|
|||
String[] emails = addressResult.getEmails();
|
||||
boolean hasEmailAddress = emails != null && emails.length > 0;
|
||||
|
||||
mFields = new boolean[MAX_BUTTON_COUNT];
|
||||
mFields[0] = true; // Add contact is always available
|
||||
mFields[1] = hasAddress;
|
||||
mFields[2] = hasPhoneNumber;
|
||||
mFields[3] = hasEmailAddress;
|
||||
fields = new boolean[MAX_BUTTON_COUNT];
|
||||
fields[0] = true; // Add contact is always available
|
||||
fields[1] = hasAddress;
|
||||
fields[2] = hasPhoneNumber;
|
||||
fields[3] = hasEmailAddress;
|
||||
|
||||
mButtonCount = 0;
|
||||
buttonCount = 0;
|
||||
for (int x = 0; x < MAX_BUTTON_COUNT; x++) {
|
||||
if (mFields[x]) {
|
||||
mButtonCount++;
|
||||
if (fields[x]) {
|
||||
buttonCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonCount() {
|
||||
return mButtonCount;
|
||||
return buttonCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -102,7 +107,7 @@ public final class AddressBookResultHandler extends ResultHandler {
|
|||
|
||||
@Override
|
||||
public void handleButtonPress(int index) {
|
||||
AddressBookParsedResult addressResult = (AddressBookParsedResult) mResult;
|
||||
AddressBookParsedResult addressResult = (AddressBookParsedResult) result;
|
||||
int action = mapIndexToAction(index);
|
||||
switch (action) {
|
||||
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.
|
||||
@Override
|
||||
public CharSequence getDisplayContents() {
|
||||
AddressBookParsedResult result = (AddressBookParsedResult) mResult;
|
||||
AddressBookParsedResult result = (AddressBookParsedResult) this.result;
|
||||
StringBuffer contents = new StringBuffer();
|
||||
ParsedResult.maybeAppend(result.getNames(), contents);
|
||||
int namesLength = contents.length();
|
||||
|
@ -178,5 +183,4 @@ public final class AddressBookResultHandler extends ResultHandler {
|
|||
public int getDisplayTitle() {
|
||||
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;
|
||||
|
||||
import android.app.Activity;
|
||||
import com.google.zxing.client.android.R;
|
||||
import com.google.zxing.client.result.CalendarParsedResult;
|
||||
import com.google.zxing.client.result.ParsedResult;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParsePosition;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
@ -28,12 +29,16 @@ import java.util.Calendar;
|
|||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
/**
|
||||
* Handles calendar entries encoded in QR Codes.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public final class CalendarResultHandler extends ResultHandler {
|
||||
|
||||
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -43,17 +48,17 @@ public final class CalendarResultHandler extends ResultHandler {
|
|||
|
||||
@Override
|
||||
public int getButtonCount() {
|
||||
return mButtons.length;
|
||||
return buttons.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonText(int index) {
|
||||
return mButtons[index];
|
||||
return buttons[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleButtonPress(int index) {
|
||||
CalendarParsedResult calendarResult = (CalendarParsedResult) mResult;
|
||||
CalendarParsedResult calendarResult = (CalendarParsedResult) result;
|
||||
switch (index) {
|
||||
case 0:
|
||||
addCalendarEvent(calendarResult.getSummary(), calendarResult.getStart(),
|
||||
|
@ -64,7 +69,7 @@ public final class CalendarResultHandler extends ResultHandler {
|
|||
|
||||
@Override
|
||||
public CharSequence getDisplayContents() {
|
||||
CalendarParsedResult calResult = (CalendarParsedResult) mResult;
|
||||
CalendarParsedResult calResult = (CalendarParsedResult) result;
|
||||
StringBuffer result = new StringBuffer();
|
||||
ParsedResult.maybeAppend(calResult.getSummary(), result);
|
||||
appendTime(calResult.getStart(), result);
|
||||
|
@ -110,5 +115,4 @@ public final class CalendarResultHandler extends ResultHandler {
|
|||
public int getDisplayTitle() {
|
||||
return R.string.result_calendar;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,14 +16,19 @@
|
|||
|
||||
package com.google.zxing.client.android.result;
|
||||
|
||||
import android.app.Activity;
|
||||
import com.google.zxing.client.android.R;
|
||||
import com.google.zxing.client.result.EmailAddressParsedResult;
|
||||
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_add_contact
|
||||
};
|
||||
|
@ -34,17 +39,17 @@ public final class EmailAddressResultHandler extends ResultHandler {
|
|||
|
||||
@Override
|
||||
public int getButtonCount() {
|
||||
return mButtons.length;
|
||||
return buttons.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonText(int index) {
|
||||
return mButtons[index];
|
||||
return buttons[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleButtonPress(int index) {
|
||||
EmailAddressParsedResult emailResult = (EmailAddressParsedResult) mResult;
|
||||
EmailAddressParsedResult emailResult = (EmailAddressParsedResult) result;
|
||||
switch (index) {
|
||||
case 0:
|
||||
sendEmailFromUri(emailResult.getMailtoURI(), null, null);
|
||||
|
@ -61,5 +66,4 @@ public final class EmailAddressResultHandler extends ResultHandler {
|
|||
public int getDisplayTitle() {
|
||||
return R.string.result_email_address;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,14 +16,19 @@
|
|||
|
||||
package com.google.zxing.client.android.result;
|
||||
|
||||
import android.app.Activity;
|
||||
import com.google.zxing.client.android.R;
|
||||
import com.google.zxing.client.result.GeoParsedResult;
|
||||
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_get_directions
|
||||
};
|
||||
|
@ -34,17 +39,17 @@ public final class GeoResultHandler extends ResultHandler {
|
|||
|
||||
@Override
|
||||
public int getButtonCount() {
|
||||
return mButtons.length;
|
||||
return buttons.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonText(int index) {
|
||||
return mButtons[index];
|
||||
return buttons[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleButtonPress(int index) {
|
||||
GeoParsedResult geoResult = (GeoParsedResult) mResult;
|
||||
GeoParsedResult geoResult = (GeoParsedResult) result;
|
||||
switch (index) {
|
||||
case 0:
|
||||
openMap(geoResult.getGeoURI());
|
||||
|
@ -59,5 +64,4 @@ public final class GeoResultHandler extends ResultHandler {
|
|||
public int getDisplayTitle() {
|
||||
return R.string.result_geo;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,44 +16,50 @@
|
|||
|
||||
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.R;
|
||||
import com.google.zxing.client.result.ISBNParsedResult;
|
||||
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_book_search,
|
||||
R.string.button_search_book_contents,
|
||||
R.string.button_custom_product_search,
|
||||
};
|
||||
|
||||
private final String mCustomProductSearch;
|
||||
private final String customProductSearch;
|
||||
|
||||
public ISBNResultHandler(Activity activity, ParsedResult result) {
|
||||
super(activity, result);
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
mCustomProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null);
|
||||
customProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
public int getButtonText(int index) {
|
||||
return mButtons[index];
|
||||
return buttons[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleButtonPress(int index) {
|
||||
ISBNParsedResult isbnResult = (ISBNParsedResult) mResult;
|
||||
ISBNParsedResult isbnResult = (ISBNParsedResult) result;
|
||||
switch (index) {
|
||||
case 0:
|
||||
openProductSearch(isbnResult.getISBN());
|
||||
|
@ -65,7 +71,7 @@ public final class ISBNResultHandler extends ResultHandler {
|
|||
searchBookContents(isbnResult.getISBN());
|
||||
break;
|
||||
case 3:
|
||||
String url = mCustomProductSearch.replace("%s", isbnResult.getISBN());
|
||||
String url = customProductSearch.replace("%s", isbnResult.getISBN());
|
||||
openURL(url);
|
||||
break;
|
||||
}
|
||||
|
@ -75,5 +81,4 @@ public final class ISBNResultHandler extends ResultHandler {
|
|||
public int getDisplayTitle() {
|
||||
return R.string.result_isbn;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,43 +16,48 @@
|
|||
|
||||
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.R;
|
||||
import com.google.zxing.client.result.ParsedResult;
|
||||
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_web_search,
|
||||
R.string.button_custom_product_search,
|
||||
};
|
||||
|
||||
private final String mCustomProductSearch;
|
||||
private final String customProductSearch;
|
||||
|
||||
public ProductResultHandler(Activity activity, ParsedResult result) {
|
||||
super(activity, result);
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
mCustomProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null);
|
||||
customProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonCount() {
|
||||
return mCustomProductSearch != null ? mButtons.length : mButtons.length - 1;
|
||||
return customProductSearch != null ? buttons.length : buttons.length - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonText(int index) {
|
||||
return mButtons[index];
|
||||
return buttons[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleButtonPress(int index) {
|
||||
ProductParsedResult productResult = (ProductParsedResult) mResult;
|
||||
ProductParsedResult productResult = (ProductParsedResult) result;
|
||||
switch (index) {
|
||||
case 0:
|
||||
openProductSearch(productResult.getNormalizedProductID());
|
||||
|
@ -61,7 +66,7 @@ public final class ProductResultHandler extends ResultHandler {
|
|||
webSearch(productResult.getNormalizedProductID());
|
||||
break;
|
||||
case 2:
|
||||
String url = mCustomProductSearch.replace("%s", productResult.getNormalizedProductID());
|
||||
String url = customProductSearch.replace("%s", productResult.getNormalizedProductID());
|
||||
openURL(url);
|
||||
break;
|
||||
}
|
||||
|
@ -71,5 +76,4 @@ public final class ProductResultHandler extends ResultHandler {
|
|||
public int getDisplayTitle() {
|
||||
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
|
||||
* proper intents to open other activities like GMail, Maps, etc.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public final class ResultButtonListener implements Button.OnClickListener {
|
||||
|
||||
final ResultHandler mResultHandler;
|
||||
final int mIndex;
|
||||
final ResultHandler resultHandler;
|
||||
final int index;
|
||||
|
||||
public ResultButtonListener(ResultHandler resultHandler, int index) {
|
||||
mResultHandler = resultHandler;
|
||||
mIndex = index;
|
||||
this.resultHandler = resultHandler;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
mResultHandler.handleButtonPress(mIndex);
|
||||
resultHandler.handleButtonPress(index);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,40 +16,50 @@
|
|||
|
||||
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.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
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.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
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 {
|
||||
|
||||
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
|
||||
private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
|
||||
|
||||
public static final int MAX_BUTTON_COUNT = 4;
|
||||
|
||||
protected final ParsedResult mResult;
|
||||
private final Activity mActivity;
|
||||
protected final ParsedResult result;
|
||||
private final Activity activity;
|
||||
|
||||
protected ResultHandler(Activity activity, ParsedResult result) {
|
||||
mResult = result;
|
||||
mActivity = activity;
|
||||
this.result = result;
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,7 +91,7 @@ public abstract class ResultHandler {
|
|||
* @return The text to be displayed.
|
||||
*/
|
||||
public CharSequence getDisplayContents() {
|
||||
String contents = mResult.getDisplayResult();
|
||||
String contents = result.getDisplayResult();
|
||||
return contents.replace("\r", "");
|
||||
}
|
||||
|
||||
|
@ -98,7 +108,7 @@ public abstract class ResultHandler {
|
|||
* @return The parsed type, e.g. URI or ISBN
|
||||
*/
|
||||
public final ParsedResultType getType() {
|
||||
return mResult.getType();
|
||||
return result.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -171,7 +181,7 @@ public abstract class ResultHandler {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -188,7 +198,7 @@ public abstract class ResultHandler {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -212,7 +222,7 @@ public abstract class ResultHandler {
|
|||
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.
|
||||
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 {
|
||||
putExtra(intent, "subject", subject);
|
||||
}
|
||||
|
@ -267,7 +277,7 @@ public abstract class ResultHandler {
|
|||
|
||||
public final void searchBookContents(String isbn) {
|
||||
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);
|
||||
launchIntent(intent);
|
||||
}
|
||||
|
@ -285,11 +295,11 @@ public abstract class ResultHandler {
|
|||
private void launchIntent(Intent intent) {
|
||||
if (intent != null) {
|
||||
try {
|
||||
mActivity.startActivity(intent);
|
||||
activity.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
|
||||
builder.setTitle(mActivity.getString(R.string.app_name));
|
||||
builder.setMessage(mActivity.getString(R.string.msg_intent_failed));
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setTitle(activity.getString(R.string.app_name));
|
||||
builder.setMessage(activity.getString(R.string.msg_intent_failed));
|
||||
builder.setPositiveButton(R.string.button_ok, null);
|
||||
builder.show();
|
||||
}
|
||||
|
@ -301,5 +311,4 @@ public abstract class ResultHandler {
|
|||
intent.putExtra(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,14 +16,19 @@
|
|||
|
||||
package com.google.zxing.client.android.result;
|
||||
|
||||
import android.app.Activity;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.client.result.ParsedResult;
|
||||
import com.google.zxing.client.result.ParsedResultType;
|
||||
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() {
|
||||
}
|
||||
|
||||
|
@ -57,22 +62,6 @@ public final class ResultHandlerFactory {
|
|||
}
|
||||
|
||||
private static ParsedResult parseResult(Result rawResult) {
|
||||
ParsedResult result = 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;
|
||||
return ResultParser.parseResult(rawResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,15 +16,20 @@
|
|||
|
||||
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.result.ParsedResult;
|
||||
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_mms
|
||||
};
|
||||
|
@ -35,17 +40,17 @@ public final class SMSResultHandler extends ResultHandler {
|
|||
|
||||
@Override
|
||||
public int getButtonCount() {
|
||||
return mButtons.length;
|
||||
return buttons.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonText(int index) {
|
||||
return mButtons[index];
|
||||
return buttons[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleButtonPress(int index) {
|
||||
SMSParsedResult smsResult = (SMSParsedResult) mResult;
|
||||
SMSParsedResult smsResult = (SMSParsedResult) result;
|
||||
switch (index) {
|
||||
case 0:
|
||||
sendSMS(smsResult.getNumber(), smsResult.getBody());
|
||||
|
@ -58,7 +63,7 @@ public final class SMSResultHandler extends ResultHandler {
|
|||
|
||||
@Override
|
||||
public CharSequence getDisplayContents() {
|
||||
SMSParsedResult smsResult = (SMSParsedResult) mResult;
|
||||
SMSParsedResult smsResult = (SMSParsedResult) result;
|
||||
StringBuffer contents = new StringBuffer();
|
||||
ParsedResult.maybeAppend(PhoneNumberUtils.formatNumber(smsResult.getNumber()), contents);
|
||||
ParsedResult.maybeAppend(smsResult.getVia(), contents);
|
||||
|
@ -72,5 +77,4 @@ public final class SMSResultHandler extends ResultHandler {
|
|||
public int getDisplayTitle() {
|
||||
return R.string.result_sms;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,15 +16,20 @@
|
|||
|
||||
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.result.ParsedResult;
|
||||
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_add_contact
|
||||
};
|
||||
|
@ -35,17 +40,17 @@ public final class TelResultHandler extends ResultHandler {
|
|||
|
||||
@Override
|
||||
public int getButtonCount() {
|
||||
return mButtons.length;
|
||||
return buttons.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonText(int index) {
|
||||
return mButtons[index];
|
||||
return buttons[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleButtonPress(int index) {
|
||||
TelParsedResult telResult = (TelParsedResult) mResult;
|
||||
TelParsedResult telResult = (TelParsedResult) result;
|
||||
switch (index) {
|
||||
case 0:
|
||||
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.
|
||||
@Override
|
||||
public CharSequence getDisplayContents() {
|
||||
String contents = mResult.getDisplayResult();
|
||||
String contents = result.getDisplayResult();
|
||||
contents = contents.replace("\r", "");
|
||||
return PhoneNumberUtils.formatNumber(contents);
|
||||
}
|
||||
|
@ -70,5 +75,4 @@ public final class TelResultHandler extends ResultHandler {
|
|||
public int getDisplayTitle() {
|
||||
return R.string.result_tel;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,16 +16,18 @@
|
|||
|
||||
package com.google.zxing.client.android.result;
|
||||
|
||||
import android.app.Activity;
|
||||
import com.google.zxing.client.android.R;
|
||||
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 {
|
||||
|
||||
private static final int[] mButtons = {
|
||||
private static final int[] buttons = {
|
||||
R.string.button_web_search,
|
||||
R.string.button_share_by_email,
|
||||
R.string.button_share_by_sms
|
||||
|
@ -37,25 +39,25 @@ public final class TextResultHandler extends ResultHandler {
|
|||
|
||||
@Override
|
||||
public int getButtonCount() {
|
||||
return mButtons.length;
|
||||
return buttons.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonText(int index) {
|
||||
return mButtons[index];
|
||||
return buttons[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleButtonPress(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
webSearch(mResult.getDisplayResult());
|
||||
webSearch(result.getDisplayResult());
|
||||
break;
|
||||
case 1:
|
||||
shareByEmail(mResult.getDisplayResult());
|
||||
shareByEmail(result.getDisplayResult());
|
||||
break;
|
||||
case 2:
|
||||
shareBySMS(mResult.getDisplayResult());
|
||||
shareBySMS(result.getDisplayResult());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -64,5 +66,4 @@ public final class TextResultHandler extends ResultHandler {
|
|||
public int getDisplayTitle() {
|
||||
return R.string.result_text;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,14 +16,19 @@
|
|||
|
||||
package com.google.zxing.client.android.result;
|
||||
|
||||
import android.app.Activity;
|
||||
import com.google.zxing.client.android.R;
|
||||
import com.google.zxing.client.result.ParsedResult;
|
||||
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_share_by_email,
|
||||
R.string.button_share_by_sms
|
||||
|
@ -35,17 +40,17 @@ public final class URIResultHandler extends ResultHandler {
|
|||
|
||||
@Override
|
||||
public int getButtonCount() {
|
||||
return mButtons.length;
|
||||
return buttons.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonText(int index) {
|
||||
return mButtons[index];
|
||||
return buttons[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleButtonPress(int index) {
|
||||
URIParsedResult uriResult = (URIParsedResult) mResult;
|
||||
URIParsedResult uriResult = (URIParsedResult) result;
|
||||
switch (index) {
|
||||
case 0:
|
||||
openURL(uriResult.getURI());
|
||||
|
@ -63,5 +68,4 @@ public final class URIResultHandler extends ResultHandler {
|
|||
public int getDisplayTitle() {
|
||||
return R.string.result_uri;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue