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:
dswitkin 2009-09-10 22:18:58 +00:00
parent e83cb0cef1
commit 833ca52c27
37 changed files with 1249 additions and 849 deletions

View file

@ -20,9 +20,16 @@ version to be published. The next versionCode will be 7, regardless of whether t
versionName is 2.31, 2.4, or 3.0. --> versionName is 2.31, 2.4, or 3.0. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.zxing.client.android" package="com.google.zxing.client.android"
android:versionName="2.93" android:versionName="3.0 alpha1"
android:versionCode="30"> android:versionCode="32">
<!-- Allows this app to run on Cupcake devices. -->
<uses-sdk android:minSdkVersion="3"/> <uses-sdk android:minSdkVersion="3"/>
<!-- Donut-specific flags which allow us to run on large and high dpi screens. -->
<supports-screens
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:anyDensity="true"/>
<application android:icon="@drawable/launcher_icon" <application android:icon="@drawable/launcher_icon"
android:label="@string/app_name"> android:label="@string/app_name">
<activity android:name=".CaptureActivity" <activity android:name=".CaptureActivity"

View file

@ -8,4 +8,4 @@
# project structure. # project structure.
# Project target. # Project target.
target=Google Inc.:Google APIs:3 target=Google Inc.:Google APIs:4

View file

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

View file

@ -29,9 +29,10 @@ import android.widget.SimpleCursorAdapter;
/** /**
* This class is only needed because I can't successfully send an ACTION_PICK intent to * This class is only needed because I can't successfully send an ACTION_PICK intent to
* com.android.browser.BrowserBookmarksPage. It can go away if that starts working in the future. * com.android.browser.BrowserBookmarksPage. It can go away if that starts working in the future.
*
* @author dswitkin@google.com (Daniel Switkin)
*/ */
public final class BookmarkPickerActivity extends ListActivity { public final class BookmarkPickerActivity extends ListActivity {
private static final String[] BOOKMARK_PROJECTION = { private static final String[] BOOKMARK_PROJECTION = {
Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL Browser.BookmarkColumns.URL
@ -48,32 +49,31 @@ public final class BookmarkPickerActivity extends ListActivity {
// Without this selection, we'd get all the history entries too // Without this selection, we'd get all the history entries too
private static final String BOOKMARK_SELECTION = "bookmark = 1"; private static final String BOOKMARK_SELECTION = "bookmark = 1";
private Cursor mCursor; private Cursor cursor;
@Override @Override
protected void onCreate(Bundle icicle) { protected void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
mCursor = getContentResolver().query(Browser.BOOKMARKS_URI, BOOKMARK_PROJECTION, cursor = getContentResolver().query(Browser.BOOKMARKS_URI, BOOKMARK_PROJECTION,
BOOKMARK_SELECTION, null, null); BOOKMARK_SELECTION, null, null);
startManagingCursor(mCursor); startManagingCursor(cursor);
ListAdapter adapter = new SimpleCursorAdapter(this, R.layout.bookmark_picker_list_item, ListAdapter adapter = new SimpleCursorAdapter(this, R.layout.bookmark_picker_list_item,
mCursor, BOOKMARK_PROJECTION, TWO_LINE_VIEW_IDS); cursor, BOOKMARK_PROJECTION, TWO_LINE_VIEW_IDS);
setListAdapter(adapter); setListAdapter(adapter);
} }
@Override @Override
protected void onListItemClick(ListView l, View view, int position, long id) { protected void onListItemClick(ListView l, View view, int position, long id) {
if (mCursor.moveToPosition(position)) { if (cursor.moveToPosition(position)) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(Browser.BookmarkColumns.TITLE, mCursor.getString(TITLE_COLUMN)); intent.putExtra(Browser.BookmarkColumns.TITLE, cursor.getString(TITLE_COLUMN));
intent.putExtra(Browser.BookmarkColumns.URL, mCursor.getString(URL_COLUMN)); intent.putExtra(Browser.BookmarkColumns.URL, cursor.getString(URL_COLUMN));
setResult(RESULT_OK, intent); setResult(RESULT_OK, intent);
} else { } else {
setResult(RESULT_CANCELED); setResult(RESULT_CANCELED);
} }
finish(); finish();
} }
} }

View file

@ -19,6 +19,7 @@ package com.google.zxing.client.android;
import com.google.zxing.ResultPoint; import com.google.zxing.ResultPoint;
import android.content.Context; import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.hardware.Camera; import android.hardware.Camera;
@ -35,47 +36,82 @@ import java.io.IOException;
* This object wraps the Camera service object and expects to be the only one talking to it. The * This object wraps the Camera service object and expects to be the only one talking to it. The
* implementation encapsulates the steps needed to take preview-sized images, which are used for * implementation encapsulates the steps needed to take preview-sized images, which are used for
* both preview and decoding. * both preview and decoding.
*
* @author dswitkin@google.com (Daniel Switkin)
*/ */
final class CameraManager { final class CameraManager {
private static final String TAG = "CameraManager"; private static final String TAG = "CameraManager";
private static final int MIN_FRAME_WIDTH = 240;
private static final int MIN_FRAME_HEIGHT = 240;
private static final int MAX_FRAME_WIDTH = 480;
private static final int MAX_FRAME_HEIGHT = 360;
private static CameraManager mCameraManager; private static CameraManager cameraManager;
private Camera mCamera; private Camera camera;
private final Context mContext; private final Context context;
private Point mScreenResolution; private Point screenResolution;
private Rect mFramingRect; private Point cameraResolution;
private Handler mPreviewHandler; private Rect framingRect;
private int mPreviewMessage; private Handler previewHandler;
private Handler mAutoFocusHandler; private int previewMessage;
private int mAutoFocusMessage; private Handler autoFocusHandler;
private boolean mInitialized; private int autoFocusMessage;
private boolean mPreviewing; private boolean initialized;
private boolean previewing;
private int previewFormat;
private String previewFormatString;
/**
* Preview frames are delivered here, which we pass on to the registered handler. Make sure to
* clear the handler so it will only receive one message.
*/
private final Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
camera.setPreviewCallback(null);
if (previewHandler != null) {
Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x,
cameraResolution.y, data);
message.sendToTarget();
previewHandler = null;
}
}
};
private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
if (autoFocusHandler != null) {
Message message = autoFocusHandler.obtainMessage(autoFocusMessage, success);
// Simulate continuous autofocus by sending a focus request every 1.5 seconds.
autoFocusHandler.sendMessageDelayed(message, 1500L);
autoFocusHandler = null;
}
}
};
public static void init(Context context) { public static void init(Context context) {
if (mCameraManager == null) { if (cameraManager == null) {
mCameraManager = new CameraManager(context); cameraManager = new CameraManager(context);
} }
} }
public static CameraManager get() { public static CameraManager get() {
return mCameraManager; return cameraManager;
} }
private CameraManager(Context context) { private CameraManager(Context context) {
mContext = context; this.context = context;
mCamera = null; camera = null;
mInitialized = false; initialized = false;
mPreviewing = false; previewing = false;
} }
public void openDriver(SurfaceHolder holder) throws IOException { public void openDriver(SurfaceHolder holder) throws IOException {
if (mCamera == null) { if (camera == null) {
mCamera = Camera.open(); camera = Camera.open();
mCamera.setPreviewDisplay(holder); camera.setPreviewDisplay(holder);
if (!mInitialized) { if (!initialized) {
mInitialized = true; initialized = true;
getScreenResolution(); getScreenResolution();
} }
@ -84,26 +120,26 @@ final class CameraManager {
} }
public void closeDriver() { public void closeDriver() {
if (mCamera != null) { if (camera != null) {
mCamera.release(); camera.release();
mCamera = null; camera = null;
} }
} }
public void startPreview() { public void startPreview() {
if (mCamera != null && !mPreviewing) { if (camera != null && !previewing) {
mCamera.startPreview(); camera.startPreview();
mPreviewing = true; previewing = true;
} }
} }
public void stopPreview() { public void stopPreview() {
if (mCamera != null && mPreviewing) { if (camera != null && previewing) {
mCamera.setPreviewCallback(null); camera.setPreviewCallback(null);
mCamera.stopPreview(); camera.stopPreview();
mPreviewHandler = null; previewHandler = null;
mAutoFocusHandler = null; autoFocusHandler = null;
mPreviewing = false; previewing = false;
} }
} }
@ -116,39 +152,48 @@ final class CameraManager {
* @param message The what field of the message to be sent. * @param message The what field of the message to be sent.
*/ */
public void requestPreviewFrame(Handler handler, int message) { public void requestPreviewFrame(Handler handler, int message) {
if (mCamera != null && mPreviewing) { if (camera != null && previewing) {
mPreviewHandler = handler; previewHandler = handler;
mPreviewMessage = message; previewMessage = message;
mCamera.setPreviewCallback(previewCallback); camera.setPreviewCallback(previewCallback);
} }
} }
public void requestAutoFocus(Handler handler, int message) { public void requestAutoFocus(Handler handler, int message) {
if (mCamera != null && mPreviewing) { if (camera != null && previewing) {
mAutoFocusHandler = handler; autoFocusHandler = handler;
mAutoFocusMessage = message; autoFocusMessage = message;
mCamera.autoFocus(autoFocusCallback); camera.autoFocus(autoFocusCallback);
} }
} }
/** /**
* Calculates the framing rect which the UI should draw to show the user where to place the * Calculates the framing rect which the UI should draw to show the user where to place the
* barcode. The actual captured image should be a bit larger than indicated because they might * barcode. This target helps with alignment as well as forces the user to hold the device
* frame the shot too tightly. This target helps with alignment as well as forces the user to hold * far enough away to ensure the image will be in focus.
* the device far enough away to ensure the image will be in focus.
* *
* @return The rectangle to draw on screen in window coordinates. * @return The rectangle to draw on screen in window coordinates.
*/ */
public Rect getFramingRect() { public Rect getFramingRect() {
if (mFramingRect == null) { if (framingRect == null) {
int size = (mScreenResolution.x < mScreenResolution.y ? mScreenResolution.x : int width = cameraResolution.x * 3 / 4;
mScreenResolution.y) * 3 / 4; if (width < MIN_FRAME_WIDTH) {
int leftOffset = (mScreenResolution.x - size) / 2; width = MIN_FRAME_WIDTH;
int topOffset = (mScreenResolution.y - size) / 2; } else if (width > MAX_FRAME_WIDTH) {
mFramingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size); width = MAX_FRAME_WIDTH;
Log.v(TAG, "Calculated framing rect: " + mFramingRect); }
int height = cameraResolution.y * 3 / 4;
if (height < MIN_FRAME_HEIGHT) {
height = MIN_FRAME_HEIGHT;
} else if (height > MAX_FRAME_HEIGHT) {
height = MAX_FRAME_HEIGHT;
}
int leftOffset = (cameraResolution.x - width) / 2;
int topOffset = (cameraResolution.y - height) / 2;
framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
Log.v(TAG, "Calculated framing rect: " + framingRect);
} }
return mFramingRect; return framingRect;
} }
/** /**
@ -171,31 +216,31 @@ final class CameraManager {
} }
/** /**
* Preview frames are delivered here, which we pass on to the registered handler. Make sure to * A factory method to build the appropriate LuminanceSource object based on the format
* clear the handler so it will only receive one message. * of the preview buffers, as described by Camera.Parameters.
*
* @param data A preview frame.
* @param width The width of the image.
* @param height The height of the image.
* @return A BaseLuminanceSource subclass.
*/ */
private final Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() { public BaseLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
public void onPreviewFrame(byte[] data, Camera camera) { Rect rect = getFramingRect();
camera.setPreviewCallback(null); switch (previewFormat) {
if (mPreviewHandler != null) { case PixelFormat.YCbCr_420_SP:
Message message = mPreviewHandler.obtainMessage(mPreviewMessage, mScreenResolution.x, case PixelFormat.YCbCr_422_SP:
mScreenResolution.y, data); return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
message.sendToTarget(); rect.width(), rect.height());
mPreviewHandler = null; default:
} // There's no PixelFormat constant for this buffer format yet.
if (previewFormatString.equals("yuv422i-yuyv")) {
return new InterleavedYUV422LuminanceSource(data, width, height, rect.left, rect.top,
rect.width(), rect.height());
}
break;
} }
}; return null;
}
private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
if (mAutoFocusHandler != null) {
Message message = mAutoFocusHandler.obtainMessage(mAutoFocusMessage, success);
// Simulate continuous autofocus by sending a focus request every 1.5 seconds.
mAutoFocusHandler.sendMessageDelayed(message, 1500L);
mAutoFocusHandler = null;
}
}
};
/** /**
* Sets the camera up to take preview images which are used for both preview and decoding. We're * Sets the camera up to take preview images which are used for both preview and decoding. We're
@ -203,13 +248,21 @@ final class CameraManager {
* specify it explicitly with setPreviewFormat(). * specify it explicitly with setPreviewFormat().
*/ */
private void setCameraParameters() { private void setCameraParameters() {
Camera.Parameters parameters = mCamera.getParameters(); Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize(); Camera.Size size = parameters.getPreviewSize();
Log.v(TAG, "Default preview size: " + size.width + ", " + size.height); Log.v(TAG, "Default preview size: " + size.width + ", " + size.height);
Log.v(TAG, "Default preview format: " + parameters.getPreviewFormat()); previewFormat = parameters.getPreviewFormat();
Log.v(TAG, "Setting preview size: " + mScreenResolution.x + ", " + mScreenResolution.y); previewFormatString = parameters.get("preview-format");
Log.v(TAG, "Default preview format: " + previewFormat);
parameters.setPreviewSize(mScreenResolution.x, mScreenResolution.y); // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
// TODO: A better solution would be to request the supported preview resolutions
// and pick the best match, but this parameter is not standardized in Cupcake.
cameraResolution = new Point();
cameraResolution.x = (screenResolution.x >> 3) << 3;
cameraResolution.y = (screenResolution.y >> 3) << 3;
Log.v(TAG, "Setting preview size: " + cameraResolution.x + ", " + cameraResolution.y);
parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
// FIXME: This is a hack to turn the flash off on the Samsung Galaxy. // FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
parameters.set("flash-value", 2); parameters.set("flash-value", 2);
@ -217,16 +270,16 @@ final class CameraManager {
// This is the standard setting to turn the flash off that all devices should honor. // This is the standard setting to turn the flash off that all devices should honor.
parameters.set("flash-mode", "off"); parameters.set("flash-mode", "off");
mCamera.setParameters(parameters); camera.setParameters(parameters);
} }
private Point getScreenResolution() { private Point getScreenResolution() {
if (mScreenResolution == null) { if (screenResolution == null) {
WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay(); Display display = manager.getDefaultDisplay();
mScreenResolution = new Point(display.getWidth(), display.getHeight()); screenResolution = new Point(display.getWidth(), display.getHeight());
} }
return mScreenResolution; return screenResolution;
} }
} }

View file

@ -16,6 +16,12 @@
package com.google.zxing.client.android; package com.google.zxing.client.android;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.client.android.result.ResultButtonListener;
import com.google.zxing.client.android.result.ResultHandler;
import com.google.zxing.client.android.result.ResultHandlerFactory;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -54,20 +60,16 @@ import android.view.WindowManager;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.client.android.result.ResultButtonListener;
import com.google.zxing.client.android.result.ResultHandler;
import com.google.zxing.client.android.result.ResultHandlerFactory;
import java.io.IOException; import java.io.IOException;
/** /**
* The barcode reader activity itself. This is loosely based on the CameraPreview * The barcode reader activity itself. This is loosely based on the CameraPreview
* example included in the Android SDK. * example included in the Android SDK.
*
* @author dswitkin@google.com (Daniel Switkin)
*/ */
public final class CaptureActivity extends Activity implements SurfaceHolder.Callback { public final class CaptureActivity extends Activity implements SurfaceHolder.Callback {
private static final String TAG = "CaptureActivity"; private static final String TAG = "CaptureActivity";
private static final int SHARE_ID = Menu.FIRST; private static final int SHARE_ID = Menu.FIRST;
@ -92,23 +94,31 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
NONE NONE
} }
public CaptureActivityHandler mHandler; public CaptureActivityHandler handler;
private ViewfinderView mViewfinderView; private ViewfinderView viewfinderView;
private View mStatusView; private View statusView;
private View mResultView; private View resultView;
private MediaPlayer mMediaPlayer; private MediaPlayer mediaPlayer;
private Result mLastResult; private Result lastResult;
private boolean mHasSurface; private boolean hasSurface;
private boolean mPlayBeep; private boolean playBeep;
private boolean mVibrate; private boolean vibrate;
private boolean mCopyToClipboard; private boolean copyToClipboard;
private Source mSource; private Source source;
private String mSourceUrl; private String sourceUrl;
private String mDecodeMode; private String decodeMode;
private String mVersionName; private String versionName;
private final OnCompletionListener 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 @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
@ -120,12 +130,12 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
setContentView(R.layout.capture); setContentView(R.layout.capture);
CameraManager.init(getApplication()); CameraManager.init(getApplication());
mViewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view); viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
mResultView = findViewById(R.id.result_view); resultView = findViewById(R.id.result_view);
mStatusView = findViewById(R.id.status_view); statusView = findViewById(R.id.status_view);
mHandler = null; handler = null;
mLastResult = null; lastResult = null;
mHasSurface = false; hasSurface = false;
showHelpOnFirstLaunch(); showHelpOnFirstLaunch();
} }
@ -136,7 +146,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view); SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder(); SurfaceHolder surfaceHolder = surfaceView.getHolder();
if (mHasSurface) { if (hasSurface) {
// The activity was paused but not stopped, so the surface still exists. Therefore // The activity was paused but not stopped, so the surface still exists. Therefore
// surfaceCreated() won't be called, so init the camera here. // surfaceCreated() won't be called, so init the camera here.
initCamera(surfaceHolder); initCamera(surfaceHolder);
@ -150,52 +160,52 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
String action = intent == null ? null : intent.getAction(); String action = intent == null ? null : intent.getAction();
String dataString = intent == null ? null : intent.getDataString(); String dataString = intent == null ? null : intent.getDataString();
if (intent != null && action != null) { if (intent != null && action != null) {
if (action.equals(Intents.Scan.ACTION) || action.equals(Intents.Scan.DEPRECATED_ACTION)) { if (action.equals(Intents.Scan.ACTION)) {
// Scan the formats the intent requested, and return the result to the calling activity. // Scan the formats the intent requested, and return the result to the calling activity.
mSource = Source.NATIVE_APP_INTENT; source = Source.NATIVE_APP_INTENT;
mDecodeMode = intent.getStringExtra(Intents.Scan.MODE); decodeMode = intent.getStringExtra(Intents.Scan.MODE);
resetStatusView(); resetStatusView();
} else if (dataString != null && dataString.contains(PRODUCT_SEARCH_URL_PREFIX) && } else if (dataString != null && dataString.contains(PRODUCT_SEARCH_URL_PREFIX) &&
dataString.contains(PRODUCT_SEARCH_URL_SUFFIX)) { dataString.contains(PRODUCT_SEARCH_URL_SUFFIX)) {
// Scan only products and send the result to mobile Product Search. // Scan only products and send the result to mobile Product Search.
mSource = Source.PRODUCT_SEARCH_LINK; source = Source.PRODUCT_SEARCH_LINK;
mSourceUrl = dataString; sourceUrl = dataString;
mDecodeMode = Intents.Scan.PRODUCT_MODE; decodeMode = Intents.Scan.PRODUCT_MODE;
resetStatusView(); resetStatusView();
} else if (dataString != null && dataString.equals(ZXING_URL)) { } else if (dataString != null && dataString.equals(ZXING_URL)) {
// Scan all formats and handle the results ourselves. // Scan all formats and handle the results ourselves.
// TODO: In the future we could allow the hyperlink to include a URL to send the results to. // TODO: In the future we could allow the hyperlink to include a URL to send the results to.
mSource = Source.ZXING_LINK; source = Source.ZXING_LINK;
mSourceUrl = dataString; sourceUrl = dataString;
mDecodeMode = null; decodeMode = null;
resetStatusView(); resetStatusView();
} else { } else {
// Scan all formats and handle the results ourselves (launched from Home). // Scan all formats and handle the results ourselves (launched from Home).
mSource = Source.NONE; source = Source.NONE;
mDecodeMode = null; decodeMode = null;
resetStatusView(); resetStatusView();
} }
} else { } else {
mSource = Source.NONE; source = Source.NONE;
mDecodeMode = null; decodeMode = null;
if (mLastResult == null) { if (lastResult == null) {
resetStatusView(); resetStatusView();
} }
} }
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
mPlayBeep = prefs.getBoolean(PreferencesActivity.KEY_PLAY_BEEP, true); playBeep = prefs.getBoolean(PreferencesActivity.KEY_PLAY_BEEP, true);
mVibrate = prefs.getBoolean(PreferencesActivity.KEY_VIBRATE, false); vibrate = prefs.getBoolean(PreferencesActivity.KEY_VIBRATE, false);
mCopyToClipboard = prefs.getBoolean(PreferencesActivity.KEY_COPY_TO_CLIPBOARD, true); copyToClipboard = prefs.getBoolean(PreferencesActivity.KEY_COPY_TO_CLIPBOARD, true);
initBeepSound(); initBeepSound();
} }
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
if (mHandler != null) { if (handler != null) {
mHandler.quitSynchronously(); handler.quitSynchronously();
mHandler = null; handler = null;
} }
CameraManager.get().closeDriver(); CameraManager.get().closeDriver();
} }
@ -203,13 +213,13 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
@Override @Override
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) { if (keyCode == KeyEvent.KEYCODE_BACK) {
if (mSource == Source.NATIVE_APP_INTENT) { if (source == Source.NATIVE_APP_INTENT) {
setResult(RESULT_CANCELED); setResult(RESULT_CANCELED);
finish(); finish();
return true; return true;
} else if ((mSource == Source.NONE || mSource == Source.ZXING_LINK) && mLastResult != null) { } else if ((source == Source.NONE || source == Source.ZXING_LINK) && lastResult != null) {
resetStatusView(); resetStatusView();
mHandler.sendEmptyMessage(R.id.restart_preview); handler.sendEmptyMessage(R.id.restart_preview);
return true; return true;
} }
} else if (keyCode == KeyEvent.KEYCODE_FOCUS || keyCode == KeyEvent.KEYCODE_CAMERA) { } else if (keyCode == KeyEvent.KEYCODE_FOCUS || keyCode == KeyEvent.KEYCODE_CAMERA) {
@ -236,7 +246,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
@Override @Override
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu); super.onPrepareOptionsMenu(menu);
menu.findItem(SHARE_ID).setVisible(mLastResult == null); menu.findItem(SHARE_ID).setVisible(lastResult == null);
return true; return true;
} }
@ -263,10 +273,10 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
} }
case ABOUT_ID: case ABOUT_ID:
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.title_about) + mVersionName); builder.setTitle(getString(R.string.title_about) + versionName);
builder.setMessage(getString(R.string.msg_about) + "\n\n" + getString(R.string.zxing_url)); builder.setMessage(getString(R.string.msg_about) + "\n\n" + getString(R.string.zxing_url));
builder.setIcon(R.drawable.zxing_icon); builder.setIcon(R.drawable.zxing_icon);
builder.setPositiveButton(R.string.button_open_browser, mAboutListener); builder.setPositiveButton(R.string.button_open_browser, aboutListener);
builder.setNegativeButton(R.string.button_cancel, null); builder.setNegativeButton(R.string.button_cancel, null);
builder.show(); builder.show();
break; break;
@ -280,22 +290,15 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
super.onConfigurationChanged(config); super.onConfigurationChanged(config);
} }
private final DialogInterface.OnClickListener mAboutListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.zxing_url)));
startActivity(intent);
}
};
public void surfaceCreated(SurfaceHolder holder) { public void surfaceCreated(SurfaceHolder holder) {
if (!mHasSurface) { if (!hasSurface) {
mHasSurface = true; hasSurface = true;
initCamera(holder); initCamera(holder);
} }
} }
public void surfaceDestroyed(SurfaceHolder holder) { public void surfaceDestroyed(SurfaceHolder holder) {
mHasSurface = false; hasSurface = false;
} }
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
@ -309,11 +312,11 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
* @param barcode A greyscale bitmap of the camera data which was decoded. * @param barcode A greyscale bitmap of the camera data which was decoded.
*/ */
public void handleDecode(Result rawResult, Bitmap barcode) { public void handleDecode(Result rawResult, Bitmap barcode) {
mLastResult = rawResult; lastResult = rawResult;
playBeepSoundAndVibrate(); playBeepSoundAndVibrate();
drawResultPoints(barcode, rawResult); drawResultPoints(barcode, rawResult);
switch (mSource) { switch (source) {
case NATIVE_APP_INTENT: case NATIVE_APP_INTENT:
case PRODUCT_SEARCH_LINK: case PRODUCT_SEARCH_LINK:
handleDecodeExternally(rawResult, barcode); handleDecodeExternally(rawResult, barcode);
@ -358,9 +361,9 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
// Put up our own UI for how to handle the decoded contents. // Put up our own UI for how to handle the decoded contents.
private void handleDecodeInternally(Result rawResult, Bitmap barcode) { private void handleDecodeInternally(Result rawResult, Bitmap barcode) {
mStatusView.setVisibility(View.GONE); statusView.setVisibility(View.GONE);
mViewfinderView.setVisibility(View.GONE); viewfinderView.setVisibility(View.GONE);
mResultView.setVisibility(View.VISIBLE); resultView.setVisibility(View.VISIBLE);
ImageView barcodeImageView = (ImageView) findViewById(R.id.barcode_image_view); ImageView barcodeImageView = (ImageView) findViewById(R.id.barcode_image_view);
barcodeImageView.setMaxWidth(MAX_RESULT_IMAGE_SIZE); barcodeImageView.setMaxWidth(MAX_RESULT_IMAGE_SIZE);
@ -398,7 +401,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
} }
} }
if (mCopyToClipboard) { if (copyToClipboard) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
clipboard.setText(displayContents); clipboard.setText(displayContents);
} }
@ -406,7 +409,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
// Briefly show the contents of the barcode, then handle the result outside Barcode Scanner. // Briefly show the contents of the barcode, then handle the result outside Barcode Scanner.
private void handleDecodeExternally(Result rawResult, Bitmap barcode) { private void handleDecodeExternally(Result rawResult, Bitmap barcode) {
mViewfinderView.drawResultBitmap(barcode); viewfinderView.drawResultBitmap(barcode);
// Since this message will only be shown for a second, just tell the user what kind of // Since this message will only be shown for a second, just tell the user what kind of
// barcode was found (e.g. contact info) rather than the full contents, which they won't // barcode was found (e.g. contact info) rather than the full contents, which they won't
@ -417,30 +420,30 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
textView.setTextSize(18.0f); textView.setTextSize(18.0f);
textView.setText(getString(resultHandler.getDisplayTitle())); textView.setText(getString(resultHandler.getDisplayTitle()));
mStatusView.setBackgroundColor(getResources().getColor(R.color.transparent)); statusView.setBackgroundColor(getResources().getColor(R.color.transparent));
if (mCopyToClipboard) { if (copyToClipboard) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
clipboard.setText(resultHandler.getDisplayContents()); clipboard.setText(resultHandler.getDisplayContents());
} }
if (mSource == Source.NATIVE_APP_INTENT) { if (source == Source.NATIVE_APP_INTENT) {
// Hand back whatever action they requested - this can be changed to Intents.Scan.ACTION when // Hand back whatever action they requested - this can be changed to Intents.Scan.ACTION when
// the deprecated intent is retired. // the deprecated intent is retired.
Intent intent = new Intent(getIntent().getAction()); Intent intent = new Intent(getIntent().getAction());
intent.putExtra(Intents.Scan.RESULT, rawResult.toString()); intent.putExtra(Intents.Scan.RESULT, rawResult.toString());
intent.putExtra(Intents.Scan.RESULT_FORMAT, rawResult.getBarcodeFormat().toString()); intent.putExtra(Intents.Scan.RESULT_FORMAT, rawResult.getBarcodeFormat().toString());
Message message = Message.obtain(mHandler, R.id.return_scan_result); Message message = Message.obtain(handler, R.id.return_scan_result);
message.obj = intent; message.obj = intent;
mHandler.sendMessageDelayed(message, INTENT_RESULT_DURATION); handler.sendMessageDelayed(message, INTENT_RESULT_DURATION);
} else if (mSource == Source.PRODUCT_SEARCH_LINK) { } else if (source == Source.PRODUCT_SEARCH_LINK) {
// Reformulate the URL which triggered us into a query, so that the request goes to the same // Reformulate the URL which triggered us into a query, so that the request goes to the same
// TLD as the scan URL. // TLD as the scan URL.
Message message = Message.obtain(mHandler, R.id.launch_product_query); Message message = Message.obtain(handler, R.id.launch_product_query);
int end = mSourceUrl.lastIndexOf("/scan"); int end = sourceUrl.lastIndexOf("/scan");
message.obj = mSourceUrl.substring(0, end) + "?q=" + message.obj = sourceUrl.substring(0, end) + "?q=" +
resultHandler.getDisplayContents().toString() + "&source=zxing"; resultHandler.getDisplayContents().toString() + "&source=zxing";
mHandler.sendMessageDelayed(message, INTENT_RESULT_DURATION); handler.sendMessageDelayed(message, INTENT_RESULT_DURATION);
} }
} }
@ -455,7 +458,7 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
int currentVersion = info.versionCode; int currentVersion = info.versionCode;
// Since we're paying to talk to the PackageManager anyway, it makes sense to cache the app // Since we're paying to talk to the PackageManager anyway, it makes sense to cache the app
// version name here for display in the about box later. // version name here for display in the about box later.
this.mVersionName = info.versionName; this.versionName = info.versionName;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int lastVersion = prefs.getInt(PreferencesActivity.KEY_HELP_VERSION_SHOWN, 0); int lastVersion = prefs.getInt(PreferencesActivity.KEY_HELP_VERSION_SHOWN, 0);
if (currentVersion > lastVersion) { if (currentVersion > lastVersion) {
@ -474,29 +477,29 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
* latency possible. * latency possible.
*/ */
private void initBeepSound() { private void initBeepSound() {
if (mPlayBeep && mMediaPlayer == null) { if (playBeep && mediaPlayer == null) {
mMediaPlayer = new MediaPlayer(); mediaPlayer = new MediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_SYSTEM); mediaPlayer.setAudioStreamType(AudioManager.STREAM_SYSTEM);
mMediaPlayer.setOnCompletionListener(mBeepListener); mediaPlayer.setOnCompletionListener(beepListener);
AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep); AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
try { try {
mMediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(),
file.getLength()); file.getLength());
file.close(); file.close();
mMediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME); mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
mMediaPlayer.prepare(); mediaPlayer.prepare();
} catch (IOException e) { } catch (IOException e) {
mMediaPlayer = null; mediaPlayer = null;
} }
} }
} }
private void playBeepSoundAndVibrate() { private void playBeepSoundAndVibrate() {
if (mPlayBeep && mMediaPlayer != null) { if (playBeep && mediaPlayer != null) {
mMediaPlayer.start(); mediaPlayer.start();
} }
if (mVibrate) { if (vibrate) {
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
vibrator.vibrate(VIBRATE_DURATION); vibrator.vibrate(VIBRATE_DURATION);
} }
@ -509,27 +512,27 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
Log.w(TAG, ioe); Log.w(TAG, ioe);
return; return;
} }
if (mHandler == null) { if (handler == null) {
boolean beginScanning = mLastResult == null; boolean beginScanning = lastResult == null;
mHandler = new CaptureActivityHandler(this, mDecodeMode, beginScanning); handler = new CaptureActivityHandler(this, decodeMode, beginScanning);
} }
} }
private void resetStatusView() { private void resetStatusView() {
mResultView.setVisibility(View.GONE); resultView.setVisibility(View.GONE);
mStatusView.setVisibility(View.VISIBLE); statusView.setVisibility(View.VISIBLE);
mStatusView.setBackgroundColor(getResources().getColor(R.color.status_view)); statusView.setBackgroundColor(getResources().getColor(R.color.status_view));
mViewfinderView.setVisibility(View.VISIBLE); viewfinderView.setVisibility(View.VISIBLE);
TextView textView = (TextView) findViewById(R.id.status_text_view); TextView textView = (TextView) findViewById(R.id.status_text_view);
textView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); textView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
textView.setTextSize(14.0f); textView.setTextSize(14.0f);
textView.setText(R.string.msg_default_status); textView.setText(R.string.msg_default_status);
mLastResult = null; lastResult = null;
} }
public void drawViewfinder() { public void drawViewfinder() {
mViewfinderView.drawViewfinder(); viewfinderView.drawViewfinder();
} }
/** /**
@ -540,5 +543,4 @@ public final class CaptureActivity extends Activity implements SurfaceHolder.Cal
mediaPlayer.seekTo(0); mediaPlayer.seekTo(0);
} }
} }
} }

View file

@ -16,6 +16,8 @@
package com.google.zxing.client.android; package com.google.zxing.client.android;
import com.google.zxing.Result;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -23,16 +25,16 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import com.google.zxing.Result;
/** /**
* This class handles all the messaging which comprises the state machine for capture. * This class handles all the messaging which comprises the state machine for capture.
*
* @author dswitkin@google.com (Daniel Switkin)
*/ */
public final class CaptureActivityHandler extends Handler { public final class CaptureActivityHandler extends Handler {
private final CaptureActivity activity;
private final CaptureActivity mActivity; private final DecodeThread decodeThread;
private final DecodeThread mDecodeThread; private State state;
private State mState;
private enum State { private enum State {
PREVIEW, PREVIEW,
@ -42,10 +44,10 @@ public final class CaptureActivityHandler extends Handler {
CaptureActivityHandler(CaptureActivity activity, String decodeMode, CaptureActivityHandler(CaptureActivity activity, String decodeMode,
boolean beginScanning) { boolean beginScanning) {
mActivity = activity; this.activity = activity;
mDecodeThread = new DecodeThread(activity, decodeMode); decodeThread = new DecodeThread(activity, decodeMode);
mDecodeThread.start(); decodeThread.start();
mState = State.SUCCESS; state = State.SUCCESS;
// Start ourselves capturing previews and decoding. // Start ourselves capturing previews and decoding.
CameraManager.get().startPreview(); CameraManager.get().startPreview();
@ -60,7 +62,7 @@ public final class CaptureActivityHandler extends Handler {
case R.id.auto_focus: case R.id.auto_focus:
// When one auto focus pass finishes, start another. This is the closest thing to // When one auto focus pass finishes, start another. This is the closest thing to
// continuous AF. It does seem to hunt a bit, but I'm not sure what else to do. // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
if (mState == State.PREVIEW) { if (state == State.PREVIEW) {
CameraManager.get().requestAutoFocus(this, R.id.auto_focus); CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
} }
break; break;
@ -68,34 +70,34 @@ public final class CaptureActivityHandler extends Handler {
restartPreviewAndDecode(); restartPreviewAndDecode();
break; break;
case R.id.decode_succeeded: case R.id.decode_succeeded:
mState = State.SUCCESS; state = State.SUCCESS;
Bundle bundle = message.getData(); Bundle bundle = message.getData();
Bitmap barcode = bundle.getParcelable(DecodeThread.BARCODE_BITMAP); Bitmap barcode = bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
mActivity.handleDecode((Result) message.obj, barcode); activity.handleDecode((Result) message.obj, barcode);
break; break;
case R.id.decode_failed: case R.id.decode_failed:
// We're decoding as fast as possible, so when one decode fails, start another. // We're decoding as fast as possible, so when one decode fails, start another.
mState = State.PREVIEW; state = State.PREVIEW;
CameraManager.get().requestPreviewFrame(mDecodeThread.mHandler, R.id.decode); CameraManager.get().requestPreviewFrame(decodeThread.handler, R.id.decode);
break; break;
case R.id.return_scan_result: case R.id.return_scan_result:
mActivity.setResult(Activity.RESULT_OK, (Intent) message.obj); activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
mActivity.finish(); activity.finish();
break; break;
case R.id.launch_product_query: case R.id.launch_product_query:
String url = (String) message.obj; String url = (String) message.obj;
mActivity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
break; break;
} }
} }
public void quitSynchronously() { public void quitSynchronously() {
mState = State.DONE; state = State.DONE;
CameraManager.get().stopPreview(); CameraManager.get().stopPreview();
Message quit = Message.obtain(mDecodeThread.mHandler, R.id.quit); Message quit = Message.obtain(decodeThread.handler, R.id.quit);
quit.sendToTarget(); quit.sendToTarget();
try { try {
mDecodeThread.join(); decodeThread.join();
} catch (InterruptedException e) { } catch (InterruptedException e) {
} }
@ -105,12 +107,11 @@ public final class CaptureActivityHandler extends Handler {
} }
private void restartPreviewAndDecode() { private void restartPreviewAndDecode() {
if (mState == State.SUCCESS) { if (state == State.SUCCESS) {
mState = State.PREVIEW; state = State.PREVIEW;
CameraManager.get().requestPreviewFrame(mDecodeThread.mHandler, R.id.decode); CameraManager.get().requestPreviewFrame(decodeThread.handler, R.id.decode);
CameraManager.get().requestAutoFocus(this, R.id.auto_focus); CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
mActivity.drawViewfinder(); activity.drawViewfinder();
} }
} }
} }

View file

@ -18,8 +18,13 @@ package com.google.zxing.client.android;
import android.provider.Contacts; import android.provider.Contacts;
/**
* The set of constants to use when sending Barcode Scanner an Intent which requests a barcode
* to be encoded.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class Contents { public final class Contents {
private Contents() { private Contents() {
} }
@ -89,24 +94,19 @@ public final class Contents {
} }
} }
// These are new constants in Contacts.Intents.Insert for Android 1.1.
// TODO: Remove these constants once we can build against the 1.1 SDK.
private static final String SECONDARY_PHONE = "secondary_phone";
private static final String TERTIARY_PHONE = "tertiary_phone";
private static final String SECONDARY_EMAIL = "secondary_email";
private static final String TERTIARY_EMAIL = "tertiary_email";
/** /**
* When using Type.CONTACT, these arrays provide the keys for adding or retrieving multiple * When using Type.CONTACT, these arrays provide the keys for adding or retrieving multiple
* phone numbers and addresses. * phone numbers and addresses.
*/ */
public static final String[] PHONE_KEYS = { public static final String[] PHONE_KEYS = {
Contacts.Intents.Insert.PHONE, SECONDARY_PHONE, TERTIARY_PHONE Contacts.Intents.Insert.PHONE,
Contacts.Intents.Insert.SECONDARY_PHONE,
Contacts.Intents.Insert.TERTIARY_PHONE
}; };
public static final String[] EMAIL_KEYS = { public static final String[] EMAIL_KEYS = {
Contacts.Intents.Insert.EMAIL, SECONDARY_EMAIL, TERTIARY_EMAIL Contacts.Intents.Insert.EMAIL,
Contacts.Intents.Insert.SECONDARY_EMAIL,
Contacts.Intents.Insert.TERTIARY_EMAIL
}; };
} }

View file

@ -25,7 +25,6 @@ import com.google.zxing.Result;
import com.google.zxing.common.GlobalHistogramBinarizer; import com.google.zxing.common.GlobalHistogramBinarizer;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.Rect;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
@ -38,19 +37,20 @@ import java.util.Vector;
/** /**
* This thread does all the heavy lifting of decoding the images. * This thread does all the heavy lifting of decoding the images.
*
* @author dswitkin@google.com (Daniel Switkin)
*/ */
final class DecodeThread extends Thread { final class DecodeThread extends Thread {
public static final String BARCODE_BITMAP = "barcode_bitmap"; public static final String BARCODE_BITMAP = "barcode_bitmap";
private static final String TAG = "DecodeThread"; private static final String TAG = "DecodeThread";
public Handler mHandler; public Handler handler;
private final CaptureActivity mActivity; private final CaptureActivity activity;
private final MultiFormatReader mMultiFormatReader; private final MultiFormatReader multiFormatReader;
DecodeThread(CaptureActivity activity, String mode) { DecodeThread(CaptureActivity activity, String mode) {
mActivity = activity; this.activity = activity;
mMultiFormatReader = new MultiFormatReader(); multiFormatReader = new MultiFormatReader();
// The prefs can't change while the thread is running, so pick them up once here. // The prefs can't change while the thread is running, so pick them up once here.
if (mode == null || mode.length() == 0) { if (mode == null || mode.length() == 0) {
@ -80,7 +80,7 @@ final class DecodeThread extends Thread {
@Override @Override
public void run() { public void run() {
Looper.prepare(); Looper.prepare();
mHandler = new Handler() { handler = new Handler() {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
switch (message.what) { switch (message.what) {
@ -104,7 +104,7 @@ final class DecodeThread extends Thread {
vector.addElement(BarcodeFormat.EAN_13); vector.addElement(BarcodeFormat.EAN_13);
vector.addElement(BarcodeFormat.EAN_8); vector.addElement(BarcodeFormat.EAN_8);
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector); hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
mMultiFormatReader.setHints(hints); multiFormatReader.setHints(hints);
} }
/** /**
@ -121,7 +121,7 @@ final class DecodeThread extends Thread {
vector.addElement(BarcodeFormat.CODE_128); vector.addElement(BarcodeFormat.CODE_128);
vector.addElement(BarcodeFormat.ITF); vector.addElement(BarcodeFormat.ITF);
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector); hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
mMultiFormatReader.setHints(hints); multiFormatReader.setHints(hints);
} }
private void setDecodeQRMode() { private void setDecodeQRMode() {
@ -129,7 +129,7 @@ final class DecodeThread extends Thread {
Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>(1); Vector<BarcodeFormat> vector = new Vector<BarcodeFormat>(1);
vector.addElement(BarcodeFormat.QR_CODE); vector.addElement(BarcodeFormat.QR_CODE);
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector); hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
mMultiFormatReader.setHints(hints); multiFormatReader.setHints(hints);
} }
/** /**
@ -148,7 +148,7 @@ final class DecodeThread extends Thread {
vector.addElement(BarcodeFormat.ITF); vector.addElement(BarcodeFormat.ITF);
vector.addElement(BarcodeFormat.QR_CODE); vector.addElement(BarcodeFormat.QR_CODE);
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector); hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
mMultiFormatReader.setHints(hints); multiFormatReader.setHints(hints);
} }
/** /**
@ -163,12 +163,10 @@ final class DecodeThread extends Thread {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
boolean success; boolean success;
Result rawResult = null; Result rawResult = null;
Rect rect = CameraManager.get().getFramingRect(); BaseLuminanceSource source = CameraManager.get().buildLuminanceSource(data, width, height);
YUVLuminanceSource source = new YUVLuminanceSource(data, width, height, rect.left, rect.top,
rect.width(), rect.height());
BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source)); BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
try { try {
rawResult = mMultiFormatReader.decodeWithState(bitmap); rawResult = multiFormatReader.decodeWithState(bitmap);
success = true; success = true;
} catch (ReaderException e) { } catch (ReaderException e) {
success = false; success = false;
@ -177,15 +175,14 @@ final class DecodeThread extends Thread {
if (success) { if (success) {
Log.v(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString()); Log.v(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
Message message = Message.obtain(mActivity.mHandler, R.id.decode_succeeded, rawResult); Message message = Message.obtain(activity.handler, R.id.decode_succeeded, rawResult);
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelable(BARCODE_BITMAP, source.renderToBitmap()); bundle.putParcelable(BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
message.setData(bundle); message.setData(bundle);
message.sendToTarget(); message.sendToTarget();
} else { } else {
Message message = Message.obtain(mActivity.mHandler, R.id.decode_failed); Message message = Message.obtain(activity.handler, R.id.decode_failed);
message.sendToTarget(); message.sendToTarget();
} }
} }
} }

View file

@ -35,20 +35,82 @@ import android.widget.TextView;
/** /**
* This class encodes data from an Intent into a QR code, and then displays it full screen so that * This class encodes data from an Intent into a QR code, and then displays it full screen so that
* another person can scan it with their device. * another person can scan it with their device.
*
* @author dswitkin@google.com (Daniel Switkin)
*/ */
public final class EncodeActivity extends Activity { public final class EncodeActivity extends Activity {
private QRCodeEncoder qrCodeEncoder;
private ProgressDialog progressDialog;
private boolean firstLayout;
private QRCodeEncoder mQRCodeEncoder; /**
private ProgressDialog mProgressDialog; * This needs to be delayed until after the first layout so that the view dimensions will be
private boolean mFirstLayout; * available.
*/
public final OnGlobalLayoutListener layoutListener = new OnGlobalLayoutListener() {
public void onGlobalLayout() {
if (firstLayout) {
View layout = findViewById(R.id.encode_view);
int width = layout.getWidth();
int height = layout.getHeight();
int smallerDimension = width < height ? width : height;
smallerDimension = smallerDimension * 7 / 8;
Intent intent = getIntent();
try {
qrCodeEncoder = new QRCodeEncoder(EncodeActivity.this, intent);
setTitle(getString(R.string.app_name) + " - " + qrCodeEncoder.getTitle());
qrCodeEncoder.requestBarcode(handler, smallerDimension);
progressDialog = ProgressDialog.show(EncodeActivity.this, null,
getString(R.string.msg_encode_in_progress), true, true, cancelListener);
} catch (IllegalArgumentException e) {
showErrorMessage(R.string.msg_encode_contents_failed);
}
firstLayout = false;
}
}
};
public final Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case R.id.encode_succeeded:
progressDialog.dismiss();
progressDialog = null;
Bitmap image = (Bitmap) message.obj;
ImageView view = (ImageView) findViewById(R.id.image_view);
view.setImageBitmap(image);
TextView contents = (TextView) findViewById(R.id.contents_text_view);
contents.setText(qrCodeEncoder.getDisplayContents());
qrCodeEncoder = null;
break;
case R.id.encode_failed:
showErrorMessage(R.string.msg_encode_barcode_failed);
qrCodeEncoder = null;
break;
}
}
};
private final OnClickListener clickListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
};
private final OnCancelListener cancelListener = new OnCancelListener() {
public void onCancel(DialogInterface dialog) {
finish();
}
};
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
Intent intent = getIntent(); Intent intent = getIntent();
if (intent != null && (intent.getAction().equals(Intents.Encode.ACTION) || if (intent != null && (intent.getAction().equals(Intents.Encode.ACTION))) {
intent.getAction().equals(Intents.Encode.DEPRECATED_ACTION))) {
setContentView(R.layout.encode); setContentView(R.layout.encode);
} else { } else {
finish(); finish();
@ -60,81 +122,18 @@ public final class EncodeActivity extends Activity {
super.onResume(); super.onResume();
View layout = findViewById(R.id.encode_view); View layout = findViewById(R.id.encode_view);
layout.getViewTreeObserver().addOnGlobalLayoutListener(mLayoutListener); layout.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
mFirstLayout = true; firstLayout = true;
} }
/**
* This needs to be delayed until after the first layout so that the view dimensions will be
* available.
*/
public final OnGlobalLayoutListener mLayoutListener = new OnGlobalLayoutListener() {
public void onGlobalLayout() {
if (mFirstLayout) {
View layout = findViewById(R.id.encode_view);
int width = layout.getWidth();
int height = layout.getHeight();
int smallerDimension = width < height ? width : height;
smallerDimension = smallerDimension * 7 / 8;
Intent intent = getIntent();
try {
mQRCodeEncoder = new QRCodeEncoder(EncodeActivity.this, intent);
setTitle(getString(R.string.app_name) + " - " + mQRCodeEncoder.getTitle());
mQRCodeEncoder.requestBarcode(mHandler, smallerDimension);
mProgressDialog = ProgressDialog.show(EncodeActivity.this, null,
getString(R.string.msg_encode_in_progress), true, true, mCancelListener);
} catch (IllegalArgumentException e) {
showErrorMessage(R.string.msg_encode_contents_failed);
}
mFirstLayout = false;
}
}
};
public final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case R.id.encode_succeeded:
mProgressDialog.dismiss();
mProgressDialog = null;
Bitmap image = (Bitmap) message.obj;
ImageView view = (ImageView) findViewById(R.id.image_view);
view.setImageBitmap(image);
TextView contents = (TextView) findViewById(R.id.contents_text_view);
contents.setText(mQRCodeEncoder.getDisplayContents());
mQRCodeEncoder = null;
break;
case R.id.encode_failed:
showErrorMessage(R.string.msg_encode_barcode_failed);
mQRCodeEncoder = null;
break;
}
}
};
private void showErrorMessage(int message) { private void showErrorMessage(int message) {
if (mProgressDialog != null) { if (progressDialog != null) {
mProgressDialog.dismiss(); progressDialog.dismiss();
mProgressDialog = null; progressDialog = null;
} }
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(message); builder.setMessage(message);
builder.setPositiveButton(R.string.button_ok, mClickListener); builder.setPositiveButton(R.string.button_ok, clickListener);
builder.show(); builder.show();
} }
private final OnClickListener mClickListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
};
private final OnCancelListener mCancelListener = new OnCancelListener() {
public void onCancel(DialogInterface dialog) {
finish();
}
};
} }

View file

@ -25,33 +25,46 @@ import android.webkit.WebViewClient;
import android.widget.Button; import android.widget.Button;
/** /**
* An HTML-based help screen with Back and Done buttons at the bottom.
*
* @author dswitkin@google.com (Daniel Switkin) * @author dswitkin@google.com (Daniel Switkin)
*/ */
public final class HelpActivity extends Activity { public final class HelpActivity extends Activity {
private static final String DEFAULT_URL = "file:///android_asset/html/index.html"; private static final String DEFAULT_URL = "file:///android_asset/html/index.html";
private WebView mWebView; private WebView webView;
private Button mBackButton; private Button backButton;
private final Button.OnClickListener backListener = new Button.OnClickListener() {
public void onClick(View view) {
webView.goBack();
}
};
private final Button.OnClickListener doneListener = new Button.OnClickListener() {
public void onClick(View view) {
finish();
}
};
@Override @Override
protected void onCreate(Bundle icicle) { protected void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
setContentView(R.layout.help); setContentView(R.layout.help);
mWebView = (WebView)findViewById(R.id.help_contents); webView = (WebView)findViewById(R.id.help_contents);
mWebView.setWebViewClient(new HelpClient()); webView.setWebViewClient(new HelpClient());
if (icicle != null) { if (icicle != null) {
mWebView.restoreState(icicle); webView.restoreState(icicle);
} else { } else {
mWebView.loadUrl(DEFAULT_URL); webView.loadUrl(DEFAULT_URL);
} }
mBackButton = (Button)findViewById(R.id.back_button); backButton = (Button)findViewById(R.id.back_button);
mBackButton.setOnClickListener(mBackListener); backButton.setOnClickListener(backListener);
Button doneButton = (Button)findViewById(R.id.done_button); Button doneButton = (Button)findViewById(R.id.done_button);
doneButton.setOnClickListener(mDoneListener); doneButton.setOnClickListener(doneListener);
} }
@Override @Override
@ -61,40 +74,26 @@ public final class HelpActivity extends Activity {
@Override @Override
protected void onSaveInstanceState(Bundle state) { protected void onSaveInstanceState(Bundle state) {
mWebView.saveState(state); webView.saveState(state);
} }
@Override @Override
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) { if (keyCode == KeyEvent.KEYCODE_BACK) {
if (mWebView.canGoBack()) { if (webView.canGoBack()) {
mWebView.goBack(); webView.goBack();
return true; return true;
} }
} }
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
private final Button.OnClickListener mBackListener = new Button.OnClickListener() {
public void onClick(View view) {
mWebView.goBack();
}
};
private final Button.OnClickListener mDoneListener = new Button.OnClickListener() {
public void onClick(View view) {
finish();
}
};
private final class HelpClient extends WebViewClient { private final class HelpClient extends WebViewClient {
@Override @Override
public void onPageFinished(WebView view, String url) { public void onPageFinished(WebView view, String url) {
setTitle(view.getTitle()); setTitle(view.getTitle());
mBackButton.setEnabled(view.canGoBack()); backButton.setEnabled(view.canGoBack());
} }
} }
} }

View file

@ -16,8 +16,13 @@
package com.google.zxing.client.android; package com.google.zxing.client.android;
/**
* This class provides the constants to use when sending an Intent to Barcode Scanner.
* These strings are effectively API and cannot be changed.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class Intents { public final class Intents {
private Intents() { private Intents() {
} }
@ -28,9 +33,6 @@ public final class Intents {
*/ */
public static final String ACTION = "com.google.zxing.client.android.SCAN"; public static final String ACTION = "com.google.zxing.client.android.SCAN";
// For compatibility only - do not use in new code, this will go away!
public static final String DEPRECATED_ACTION = "com.android.barcodes.SCAN";
/** /**
* By default, sending Scan.ACTION will decode all barcodes that we understand. However it * By default, sending Scan.ACTION will decode all barcodes that we understand. However it
* may be useful to limit scanning to certain formats. Use Intent.putExtra(MODE, value) with * may be useful to limit scanning to certain formats. Use Intent.putExtra(MODE, value) with
@ -79,9 +81,6 @@ public final class Intents {
*/ */
public static final String ACTION = "com.google.zxing.client.android.ENCODE"; public static final String ACTION = "com.google.zxing.client.android.ENCODE";
// For compatibility only - do not use in new code, this will go away!
public static final String DEPRECATED_ACTION = "com.android.barcodes.ENCODE";
/** /**
* The data to encode. Use Intent.putExtra(DATA, data) where data is either a String or a * The data to encode. Use Intent.putExtra(DATA, data) where data is either a String or a
* Bundle, depending on the type and format specified. Non-QR Code formats should * Bundle, depending on the type and format specified. Non-QR Code formats should
@ -112,9 +111,6 @@ public final class Intents {
*/ */
public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS"; public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS";
// For compatibility only - do not use in new code, this will go away!
public static final String DEPRECATED_ACTION = "com.android.barcodes.SEARCH_BOOK_CONTENTS";
/** /**
* The book to search, identified by ISBN number. * The book to search, identified by ISBN number.
*/ */
@ -139,5 +135,4 @@ public final class Intents {
private Share() { private Share() {
} }
} }
} }

View file

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

View file

@ -22,9 +22,10 @@ import java.util.HashMap;
/** /**
* Handles any locale-specific logic for the client. * Handles any locale-specific logic for the client.
*
* @author Sean Owen
*/ */
public final class LocaleManager { public final class LocaleManager {
private static final String DEFAULT_TLD = "com"; private static final String DEFAULT_TLD = "com";
private static final Map<Locale,String> GOOGLE_COUNTRY_TLD; private static final Map<Locale,String> GOOGLE_COUNTRY_TLD;
static { static {
@ -93,5 +94,4 @@ public final class LocaleManager {
} }
return tld; return tld;
} }
} }

View file

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

View file

@ -23,6 +23,11 @@ import android.preference.CheckBoxPreference;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
/**
* The main settings activity.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class PreferencesActivity extends PreferenceActivity public final class PreferencesActivity extends PreferenceActivity
implements OnSharedPreferenceChangeListener { implements OnSharedPreferenceChangeListener {
@ -36,8 +41,8 @@ public final class PreferencesActivity extends PreferenceActivity
static final String KEY_HELP_VERSION_SHOWN = "preferences_help_version_shown"; static final String KEY_HELP_VERSION_SHOWN = "preferences_help_version_shown";
CheckBoxPreference mDecode1D; CheckBoxPreference decode1D;
CheckBoxPreference mDecodeQR; CheckBoxPreference decodeQR;
@Override @Override
protected void onCreate(Bundle icicle) { protected void onCreate(Bundle icicle) {
@ -46,19 +51,18 @@ public final class PreferencesActivity extends PreferenceActivity
PreferenceScreen preferences = getPreferenceScreen(); PreferenceScreen preferences = getPreferenceScreen();
preferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(this); preferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
mDecode1D = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_1D); decode1D = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_1D);
mDecodeQR = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_QR); decodeQR = (CheckBoxPreference) preferences.findPreference(KEY_DECODE_QR);
} }
// Prevent the user from turning off both decode options // Prevent the user from turning off both decode options
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(KEY_DECODE_1D)) { if (key.equals(KEY_DECODE_1D)) {
mDecodeQR.setEnabled(mDecode1D.isChecked()); decodeQR.setEnabled(decode1D.isChecked());
mDecodeQR.setChecked(true); decodeQR.setChecked(true);
} else if (key.equals(KEY_DECODE_QR)) { } else if (key.equals(KEY_DECODE_QR)) {
mDecode1D.setEnabled(mDecodeQR.isChecked()); decode1D.setEnabled(decodeQR.isChecked());
mDecode1D.setChecked(true); decode1D.setChecked(true);
} }
} }
} }

View file

@ -16,6 +16,11 @@
package com.google.zxing.client.android; package com.google.zxing.client.android;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -23,48 +28,49 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.provider.Contacts; import android.provider.Contacts;
import android.util.Log;
import android.telephony.PhoneNumberUtils; import android.telephony.PhoneNumberUtils;
import com.google.zxing.BarcodeFormat; import android.util.Log;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
/**
* This class does the work of decoding the user's request and extracting all the data
* to be encoded in a QR Code.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class QRCodeEncoder { public final class QRCodeEncoder {
private final Activity activity;
private final Activity mActivity; private String contents;
private String mContents; private String displayContents;
private String mDisplayContents; private String title;
private String mTitle; private BarcodeFormat format;
private BarcodeFormat mFormat;
public QRCodeEncoder(Activity activity, Intent intent) { public QRCodeEncoder(Activity activity, Intent intent) {
mActivity = activity; this.activity = activity;
if (!encodeContents(intent)) { if (!encodeContents(intent)) {
throw new IllegalArgumentException("No valid data to encode."); throw new IllegalArgumentException("No valid data to encode.");
} }
} }
public void requestBarcode(Handler handler, int pixelResolution) { public void requestBarcode(Handler handler, int pixelResolution) {
Thread encodeThread = new EncodeThread(mContents, handler, pixelResolution, Thread encodeThread = new EncodeThread(contents, handler, pixelResolution,
mFormat); format);
encodeThread.start(); encodeThread.start();
} }
public String getContents() { public String getContents() {
return mContents; return contents;
} }
public String getDisplayContents() { public String getDisplayContents() {
return mDisplayContents; return displayContents;
} }
public String getTitle() { public String getTitle() {
return mTitle; return title;
} }
public String getFormat() { public String getFormat() {
return mFormat.toString(); return format.toString();
} }
// It would be nice if the string encoding lived in the core ZXing library, // It would be nice if the string encoding lived in the core ZXing library,
@ -82,59 +88,59 @@ public final class QRCodeEncoder {
if (type == null || type.length() == 0) { if (type == null || type.length() == 0) {
return false; return false;
} }
mFormat = BarcodeFormat.QR_CODE; this.format = BarcodeFormat.QR_CODE;
encodeQRCodeContents(intent, type); encodeQRCodeContents(intent, type);
} else { } else {
String data = intent.getStringExtra(Intents.Encode.DATA); String data = intent.getStringExtra(Intents.Encode.DATA);
if (data != null && data.length() != 0) { if (data != null && data.length() != 0) {
mContents = data; contents = data;
mDisplayContents = data; displayContents = data;
mTitle = mActivity.getString(R.string.contents_text); title = activity.getString(R.string.contents_text);
if (format.equals(Contents.Format.CODE_128)) if (format.equals(Contents.Format.CODE_128))
mFormat = BarcodeFormat.CODE_128; this.format = BarcodeFormat.CODE_128;
else if (format.equals(Contents.Format.CODE_39)) else if (format.equals(Contents.Format.CODE_39))
mFormat = BarcodeFormat.CODE_39; this.format = BarcodeFormat.CODE_39;
else if (format.equals(Contents.Format.EAN_8)) else if (format.equals(Contents.Format.EAN_8))
mFormat = BarcodeFormat.EAN_8; this.format = BarcodeFormat.EAN_8;
else if (format.equals(Contents.Format.EAN_13)) else if (format.equals(Contents.Format.EAN_13))
mFormat = BarcodeFormat.EAN_13; this.format = BarcodeFormat.EAN_13;
else if (format.equals(Contents.Format.UPC_A)) else if (format.equals(Contents.Format.UPC_A))
mFormat = BarcodeFormat.UPC_A; this.format = BarcodeFormat.UPC_A;
else if (format.equals(Contents.Format.UPC_E)) else if (format.equals(Contents.Format.UPC_E))
mFormat = BarcodeFormat.UPC_E; this.format = BarcodeFormat.UPC_E;
} }
} }
return mContents != null && mContents.length() > 0; return contents != null && contents.length() > 0;
} }
private void encodeQRCodeContents(Intent intent, String type) { private void encodeQRCodeContents(Intent intent, String type) {
if (type.equals(Contents.Type.TEXT)) { if (type.equals(Contents.Type.TEXT)) {
String data = intent.getStringExtra(Intents.Encode.DATA); String data = intent.getStringExtra(Intents.Encode.DATA);
if (data != null && data.length() > 0) { if (data != null && data.length() > 0) {
mContents = data; contents = data;
mDisplayContents = data; displayContents = data;
mTitle = mActivity.getString(R.string.contents_text); title = activity.getString(R.string.contents_text);
} }
} else if (type.equals(Contents.Type.EMAIL)) { } else if (type.equals(Contents.Type.EMAIL)) {
String data = intent.getStringExtra(Intents.Encode.DATA); String data = intent.getStringExtra(Intents.Encode.DATA);
if (data != null && data.length() > 0) { if (data != null && data.length() > 0) {
mContents = "mailto:" + data; contents = "mailto:" + data;
mDisplayContents = data; displayContents = data;
mTitle = mActivity.getString(R.string.contents_email); title = activity.getString(R.string.contents_email);
} }
} else if (type.equals(Contents.Type.PHONE)) { } else if (type.equals(Contents.Type.PHONE)) {
String data = intent.getStringExtra(Intents.Encode.DATA); String data = intent.getStringExtra(Intents.Encode.DATA);
if (data != null && data.length() > 0) { if (data != null && data.length() > 0) {
mContents = "tel:" + data; contents = "tel:" + data;
mDisplayContents = PhoneNumberUtils.formatNumber(data); displayContents = PhoneNumberUtils.formatNumber(data);
mTitle = mActivity.getString(R.string.contents_phone); title = activity.getString(R.string.contents_phone);
} }
} else if (type.equals(Contents.Type.SMS)) { } else if (type.equals(Contents.Type.SMS)) {
String data = intent.getStringExtra(Intents.Encode.DATA); String data = intent.getStringExtra(Intents.Encode.DATA);
if (data != null && data.length() > 0) { if (data != null && data.length() > 0) {
mContents = "sms:" + data; contents = "sms:" + data;
mDisplayContents = PhoneNumberUtils.formatNumber(data); displayContents = PhoneNumberUtils.formatNumber(data);
mTitle = mActivity.getString(R.string.contents_sms); title = activity.getString(R.string.contents_sms);
} }
} else if (type.equals(Contents.Type.CONTACT)) { } else if (type.equals(Contents.Type.CONTACT)) {
Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA); Bundle bundle = intent.getBundleExtra(Intents.Encode.DATA);
@ -169,12 +175,12 @@ public final class QRCodeEncoder {
// Make sure we've encoded at least one field. // Make sure we've encoded at least one field.
if (newDisplayContents.length() > 0) { if (newDisplayContents.length() > 0) {
newContents.append(';'); newContents.append(';');
mContents = newContents.toString(); contents = newContents.toString();
mDisplayContents = newDisplayContents.toString(); displayContents = newDisplayContents.toString();
mTitle = mActivity.getString(R.string.contents_contact); title = activity.getString(R.string.contents_contact);
} else { } else {
mContents = null; contents = null;
mDisplayContents = null; displayContents = null;
} }
} }
} else if (type.equals(Contents.Type.LOCATION)) { } else if (type.equals(Contents.Type.LOCATION)) {
@ -184,36 +190,35 @@ public final class QRCodeEncoder {
float latitude = bundle.getFloat("LAT", Float.MAX_VALUE); float latitude = bundle.getFloat("LAT", Float.MAX_VALUE);
float longitude = bundle.getFloat("LONG", Float.MAX_VALUE); float longitude = bundle.getFloat("LONG", Float.MAX_VALUE);
if (latitude != Float.MAX_VALUE && longitude != Float.MAX_VALUE) { if (latitude != Float.MAX_VALUE && longitude != Float.MAX_VALUE) {
mContents = "geo:" + latitude + ',' + longitude; contents = "geo:" + latitude + ',' + longitude;
mDisplayContents = latitude + "," + longitude; displayContents = latitude + "," + longitude;
mTitle = mActivity.getString(R.string.contents_location); title = activity.getString(R.string.contents_location);
} }
} }
} }
} }
private static final class EncodeThread extends Thread { private static final class EncodeThread extends Thread {
private static final String TAG = "EncodeThread"; private static final String TAG = "EncodeThread";
private final String mContents; private final String contents;
private final Handler mHandler; private final Handler handler;
private final int mPixelResolution; private final int pixelResolution;
private final BarcodeFormat mFormat; private final BarcodeFormat format;
EncodeThread(String contents, Handler handler, int pixelResolution, EncodeThread(String contents, Handler handler, int pixelResolution,
BarcodeFormat format) { BarcodeFormat format) {
mContents = contents; this.contents = contents;
mHandler = handler; this.handler = handler;
mPixelResolution = pixelResolution; this.pixelResolution = pixelResolution;
mFormat = format; this.format = format;
} }
@Override @Override
public void run() { public void run() {
try { try {
ByteMatrix result = new MultiFormatWriter().encode(mContents, ByteMatrix result = new MultiFormatWriter().encode(contents, format,
mFormat, mPixelResolution, mPixelResolution); pixelResolution, pixelResolution);
int width = result.getWidth(); int width = result.getWidth();
int height = result.getHeight(); int height = result.getHeight();
byte[][] array = result.getArray(); byte[][] array = result.getArray();
@ -228,19 +233,18 @@ public final class QRCodeEncoder {
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height); bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
Message message = Message.obtain(mHandler, R.id.encode_succeeded); Message message = Message.obtain(handler, R.id.encode_succeeded);
message.obj = bitmap; message.obj = bitmap;
message.sendToTarget(); message.sendToTarget();
} catch (WriterException e) { } catch (WriterException e) {
Log.e(TAG, e.toString()); Log.e(TAG, e.toString());
Message message = Message.obtain(mHandler, R.id.encode_failed); Message message = Message.obtain(handler, R.id.encode_failed);
message.sendToTarget(); message.sendToTarget();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.e(TAG, e.toString()); Log.e(TAG, e.toString());
Message message = Message.obtain(mHandler, R.id.encode_failed); Message message = Message.obtain(handler, R.id.encode_failed);
message.sendToTarget(); message.sendToTarget();
} }
} }
} }
} }

View file

@ -48,17 +48,53 @@ import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
* Uses Google Book Search to find a word or phrase in the requested book.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class SearchBookContentsActivity extends Activity { public final class SearchBookContentsActivity extends Activity {
private static final String TAG = "SearchBookContents"; private static final String TAG = "SearchBookContents";
private static final String USER_AGENT = "ZXing (Android)"; private static final String USER_AGENT = "ZXing (Android)";
private NetworkThread mNetworkThread; private NetworkThread networkThread;
private String mISBN; private String isbn;
private EditText mQueryTextView; private EditText queryTextView;
private Button mQueryButton; private Button queryButton;
private ListView mResultListView; private ListView resultListView;
private TextView mHeaderView; private TextView headerView;
public final Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case R.id.search_book_contents_succeeded:
handleSearchResults((JSONObject) message.obj);
resetForNewQuery();
break;
case R.id.search_book_contents_failed:
resetForNewQuery();
headerView.setText(R.string.msg_sbc_failed);
break;
}
}
};
private final Button.OnClickListener buttonListener = new Button.OnClickListener() {
public void onClick(View view) {
launchSearch();
}
};
private final View.OnKeyListener keyListener = new View.OnKeyListener() {
public boolean onKey(View view, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_ENTER) {
launchSearch();
return true;
}
return false;
}
};
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
@ -69,39 +105,38 @@ public final class SearchBookContentsActivity extends Activity {
CookieManager.getInstance().removeExpiredCookie(); CookieManager.getInstance().removeExpiredCookie();
Intent intent = getIntent(); Intent intent = getIntent();
if (intent == null || (!intent.getAction().equals(Intents.SearchBookContents.ACTION) && if (intent == null || (!intent.getAction().equals(Intents.SearchBookContents.ACTION))) {
!intent.getAction().equals(Intents.SearchBookContents.DEPRECATED_ACTION))) {
finish(); finish();
return; return;
} }
mISBN = intent.getStringExtra(Intents.SearchBookContents.ISBN); isbn = intent.getStringExtra(Intents.SearchBookContents.ISBN);
setTitle(getString(R.string.sbc_name) + ": ISBN " + mISBN); setTitle(getString(R.string.sbc_name) + ": ISBN " + isbn);
setContentView(R.layout.search_book_contents); setContentView(R.layout.search_book_contents);
mQueryTextView = (EditText) findViewById(R.id.query_text_view); queryTextView = (EditText) findViewById(R.id.query_text_view);
String initialQuery = intent.getStringExtra(Intents.SearchBookContents.QUERY); String initialQuery = intent.getStringExtra(Intents.SearchBookContents.QUERY);
if (initialQuery != null && initialQuery.length() > 0) { if (initialQuery != null && initialQuery.length() > 0) {
// Populate the search box but don't trigger the search // Populate the search box but don't trigger the search
mQueryTextView.setText(initialQuery); queryTextView.setText(initialQuery);
} }
mQueryTextView.setOnKeyListener(mKeyListener); queryTextView.setOnKeyListener(keyListener);
mQueryButton = (Button) findViewById(R.id.query_button); queryButton = (Button) findViewById(R.id.query_button);
mQueryButton.setOnClickListener(mButtonListener); queryButton.setOnClickListener(buttonListener);
mResultListView = (ListView) findViewById(R.id.result_list_view); resultListView = (ListView) findViewById(R.id.result_list_view);
LayoutInflater factory = LayoutInflater.from(this); LayoutInflater factory = LayoutInflater.from(this);
mHeaderView = (TextView) factory.inflate(R.layout.search_book_contents_header, headerView = (TextView) factory.inflate(R.layout.search_book_contents_header,
mResultListView, false); resultListView, false);
mResultListView.addHeaderView(mHeaderView); resultListView.addHeaderView(headerView);
} }
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
mQueryTextView.selectAll(); queryTextView.selectAll();
} }
@Override @Override
@ -110,55 +145,23 @@ public final class SearchBookContentsActivity extends Activity {
super.onConfigurationChanged(config); super.onConfigurationChanged(config);
} }
public final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case R.id.search_book_contents_succeeded:
handleSearchResults((JSONObject) message.obj);
resetForNewQuery();
break;
case R.id.search_book_contents_failed:
resetForNewQuery();
mHeaderView.setText(R.string.msg_sbc_failed);
break;
}
}
};
private void resetForNewQuery() { private void resetForNewQuery() {
mNetworkThread = null; networkThread = null;
mQueryTextView.setEnabled(true); queryTextView.setEnabled(true);
mQueryTextView.selectAll(); queryTextView.selectAll();
mQueryButton.setEnabled(true); queryButton.setEnabled(true);
} }
private final Button.OnClickListener mButtonListener = new Button.OnClickListener() {
public void onClick(View view) {
launchSearch();
}
};
private final View.OnKeyListener mKeyListener = new View.OnKeyListener() {
public boolean onKey(View view, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_ENTER) {
launchSearch();
return true;
}
return false;
}
};
private void launchSearch() { private void launchSearch() {
if (mNetworkThread == null) { if (networkThread == null) {
String query = mQueryTextView.getText().toString(); String query = queryTextView.getText().toString();
if (query != null && query.length() > 0) { if (query != null && query.length() > 0) {
mNetworkThread = new NetworkThread(mISBN, query, mHandler); networkThread = new NetworkThread(isbn, query, handler);
mNetworkThread.start(); networkThread.start();
mHeaderView.setText(R.string.msg_sbc_searching_book); headerView.setText(R.string.msg_sbc_searching_book);
mResultListView.setAdapter(null); resultListView.setAdapter(null);
mQueryTextView.setEnabled(false); queryTextView.setEnabled(false);
mQueryButton.setEnabled(false); queryButton.setEnabled(false);
} }
} }
} }
@ -168,26 +171,26 @@ public final class SearchBookContentsActivity extends Activity {
private void handleSearchResults(JSONObject json) { private void handleSearchResults(JSONObject json) {
try { try {
int count = json.getInt("number_of_results"); int count = json.getInt("number_of_results");
mHeaderView.setText("Found " + (count == 1 ? "1 result" : count + " results")); headerView.setText("Found " + (count == 1 ? "1 result" : count + " results"));
if (count > 0) { if (count > 0) {
JSONArray results = json.getJSONArray("search_results"); JSONArray results = json.getJSONArray("search_results");
SearchBookContentsResult.setQuery(mQueryTextView.getText().toString()); SearchBookContentsResult.setQuery(queryTextView.getText().toString());
List<SearchBookContentsResult> items = new ArrayList<SearchBookContentsResult>(count); List<SearchBookContentsResult> items = new ArrayList<SearchBookContentsResult>(count);
for (int x = 0; x < count; x++) { for (int x = 0; x < count; x++) {
items.add(parseResult(results.getJSONObject(x))); items.add(parseResult(results.getJSONObject(x)));
} }
mResultListView.setAdapter(new SearchBookContentsAdapter(this, items)); resultListView.setAdapter(new SearchBookContentsAdapter(this, items));
} else { } else {
String searchable = json.optString("searchable"); String searchable = json.optString("searchable");
if ("false".equals(searchable)) { if ("false".equals(searchable)) {
mHeaderView.setText(R.string.msg_sbc_book_not_searchable); headerView.setText(R.string.msg_sbc_book_not_searchable);
} }
mResultListView.setAdapter(null); resultListView.setAdapter(null);
} }
} catch (JSONException e) { } catch (JSONException e) {
Log.e(TAG, e.toString()); Log.e(TAG, e.toString());
mResultListView.setAdapter(null); resultListView.setAdapter(null);
mHeaderView.setText(R.string.msg_sbc_failed); headerView.setText(R.string.msg_sbc_failed);
} }
} }
@ -223,15 +226,14 @@ public final class SearchBookContentsActivity extends Activity {
} }
private static final class NetworkThread extends Thread { private static final class NetworkThread extends Thread {
private final String isbn;
private final String mISBN; private final String query;
private final String mQuery; private final Handler handler;
private final Handler mHandler;
NetworkThread(String isbn, String query, Handler handler) { NetworkThread(String isbn, String query, Handler handler) {
mISBN = isbn; this.isbn = isbn;
mQuery = query; this.query = query;
mHandler = handler; this.handler = handler;
} }
@Override @Override
@ -241,8 +243,8 @@ public final class SearchBookContentsActivity extends Activity {
// These return a JSON result which describes if and where the query was found. This API may // These return a JSON result which describes if and where the query was found. This API may
// break or disappear at any time in the future. Since this is an API call rather than a // break or disappear at any time in the future. Since this is an API call rather than a
// website, we don't use LocaleManager to change the TLD. // website, we don't use LocaleManager to change the TLD.
URI uri = new URI("http", null, "www.google.com", -1, "/books", "vid=isbn" + mISBN + URI uri = new URI("http", null, "www.google.com", -1, "/books", "vid=isbn" + isbn +
"&jscmd=SearchWithinVolume2&q=" + mQuery, null); "&jscmd=SearchWithinVolume2&q=" + query, null);
HttpUriRequest get = new HttpGet(uri); HttpUriRequest get = new HttpGet(uri);
get.setHeader("cookie", getCookie(uri.toString())); get.setHeader("cookie", getCookie(uri.toString()));
client = AndroidHttpClient.newInstance(USER_AGENT); client = AndroidHttpClient.newInstance(USER_AGENT);
@ -255,17 +257,17 @@ public final class SearchBookContentsActivity extends Activity {
JSONObject json = new JSONObject(jsonHolder.toString(getEncoding(entity))); JSONObject json = new JSONObject(jsonHolder.toString(getEncoding(entity)));
jsonHolder.close(); jsonHolder.close();
Message message = Message.obtain(mHandler, R.id.search_book_contents_succeeded); Message message = Message.obtain(handler, R.id.search_book_contents_succeeded);
message.obj = json; message.obj = json;
message.sendToTarget(); message.sendToTarget();
} else { } else {
Log.e(TAG, "HTTP returned " + response.getStatusLine().getStatusCode() + " for " + uri); Log.e(TAG, "HTTP returned " + response.getStatusLine().getStatusCode() + " for " + uri);
Message message = Message.obtain(mHandler, R.id.search_book_contents_failed); Message message = Message.obtain(handler, R.id.search_book_contents_failed);
message.sendToTarget(); message.sendToTarget();
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, e.toString()); Log.e(TAG, e.toString());
Message message = Message.obtain(mHandler, R.id.search_book_contents_failed); Message message = Message.obtain(handler, R.id.search_book_contents_failed);
message.sendToTarget(); message.sendToTarget();
} finally { } finally {
if (client != null) { if (client != null) {
@ -316,5 +318,4 @@ public final class SearchBookContentsActivity extends Activity {
// return "UTF-8"; // return "UTF-8";
} }
} }
} }

View file

@ -24,8 +24,12 @@ import android.widget.ArrayAdapter;
import java.util.List; import java.util.List;
/**
* Manufactures list items which represent SBC results.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class SearchBookContentsAdapter extends ArrayAdapter<SearchBookContentsResult> { public final class SearchBookContentsAdapter extends ArrayAdapter<SearchBookContentsResult> {
public SearchBookContentsAdapter(Context context, List<SearchBookContentsResult> items) { public SearchBookContentsAdapter(Context context, List<SearchBookContentsResult> items) {
super(context, R.layout.search_book_contents_list_item, 0, items); super(context, R.layout.search_book_contents_list_item, 0, items);
} }
@ -50,5 +54,4 @@ public final class SearchBookContentsAdapter extends ArrayAdapter<SearchBookCont
listItem.set(result); listItem.set(result);
return listItem; return listItem;
} }
} }

View file

@ -25,10 +25,14 @@ import android.util.AttributeSet;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
/**
* A list item which displays the page number and snippet of this search result.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class SearchBookContentsListItem extends LinearLayout { public final class SearchBookContentsListItem extends LinearLayout {
private TextView pageNumberView;
private TextView mPageNumberView; private TextView snippetView;
private TextView mSnippetView;
SearchBookContentsListItem(Context context) { SearchBookContentsListItem(Context context) {
super(context); super(context);
@ -41,12 +45,12 @@ public final class SearchBookContentsListItem extends LinearLayout {
@Override @Override
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
mPageNumberView = (TextView) findViewById(R.id.page_number_view); pageNumberView = (TextView) findViewById(R.id.page_number_view);
mSnippetView = (TextView) findViewById(R.id.snippet_view); snippetView = (TextView) findViewById(R.id.snippet_view);
} }
public void set(SearchBookContentsResult result) { public void set(SearchBookContentsResult result) {
mPageNumberView.setText(result.getPageNumber()); pageNumberView.setText(result.getPageNumber());
String snippet = result.getSnippet(); String snippet = result.getSnippet();
if (snippet.length() > 0) { if (snippet.length() > 0) {
if (result.getValidSnippet()) { if (result.getValidSnippet()) {
@ -64,14 +68,13 @@ public final class SearchBookContentsListItem extends LinearLayout {
styledSnippet.setSpan(boldSpan, pos, pos + queryLength, 0); styledSnippet.setSpan(boldSpan, pos, pos + queryLength, 0);
offset = pos + queryLength; offset = pos + queryLength;
} }
mSnippetView.setText(styledSnippet); snippetView.setText(styledSnippet);
} else { } else {
// This may be an error message, so don't try to bold the query terms within it // This may be an error message, so don't try to bold the query terms within it
mSnippetView.setText(snippet); snippetView.setText(snippet);
} }
} else { } else {
mSnippetView.setText(""); snippetView.setText("");
} }
} }
} }

View file

@ -16,38 +16,41 @@
package com.google.zxing.client.android; package com.google.zxing.client.android;
/**
* The underlying data for a SBC result.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class SearchBookContentsResult { public final class SearchBookContentsResult {
private static String query;
private static String sQuery; private final String pageNumber;
private final String snippet;
private final String mPageNumber; private final boolean validSnippet;
private final String mSnippet;
private final boolean mValidSnippet;
public SearchBookContentsResult(String pageNumber, String snippet, boolean validSnippet) { public SearchBookContentsResult(String pageNumber, String snippet, boolean validSnippet) {
mPageNumber = pageNumber; this.pageNumber = pageNumber;
mSnippet = snippet; this.snippet = snippet;
mValidSnippet = validSnippet; this.validSnippet = validSnippet;
} }
public static void setQuery(String query) { public static void setQuery(String query) {
sQuery = query; SearchBookContentsResult.query = query;
} }
public String getPageNumber() { public String getPageNumber() {
return mPageNumber; return pageNumber;
} }
public String getSnippet() { public String getSnippet() {
return mSnippet; return snippet;
} }
public boolean getValidSnippet() { public boolean getValidSnippet() {
return mValidSnippet; return validSnippet;
} }
public static String getQuery() { public static String getQuery() {
return sQuery; return query;
} }
} }

View file

@ -29,8 +29,13 @@ import android.text.ClipboardManager;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
/**
* Barcode Scanner can share data like contacts and bookmarks by displaying a QR Code on screen,
* such that another user can scan the barcode with their phone.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ShareActivity extends Activity { public final class ShareActivity extends Activity {
private static final int PICK_BOOKMARK = 0; private static final int PICK_BOOKMARK = 0;
private static final int PICK_CONTACT = 1; private static final int PICK_CONTACT = 1;
@ -51,43 +56,16 @@ public final class ShareActivity extends Activity {
Contacts.PhonesColumns.NUMBER // 1 Contacts.PhonesColumns.NUMBER // 1
}; };
private Button mClipboardButton; private Button clipboardButton;
@Override private final Button.OnClickListener contactListener = new Button.OnClickListener() {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.share);
Button mContactButton = (Button) findViewById(R.id.contact_button);
mContactButton.setOnClickListener(mContactListener);
Button mBookmarkButton = (Button) findViewById(R.id.bookmark_button);
mBookmarkButton.setOnClickListener(mBookmarkListener);
mClipboardButton = (Button) findViewById(R.id.clipboard_button);
mClipboardButton.setOnClickListener(mClipboardListener);
}
@Override
protected void onResume() {
super.onResume();
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
if (clipboard.hasText()) {
mClipboardButton.setEnabled(true);
mClipboardButton.setText(R.string.button_share_clipboard);
} else {
mClipboardButton.setEnabled(false);
mClipboardButton.setText(R.string.button_clipboard_empty);
}
}
private final Button.OnClickListener mContactListener = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
startActivityForResult(new Intent(Intent.ACTION_PICK, Contacts.People.CONTENT_URI), startActivityForResult(new Intent(Intent.ACTION_PICK, Contacts.People.CONTENT_URI),
PICK_CONTACT); PICK_CONTACT);
} }
}; };
private final Button.OnClickListener mBookmarkListener = new Button.OnClickListener() { private final Button.OnClickListener bookmarkListener = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_PICK); Intent intent = new Intent(Intent.ACTION_PICK);
intent.setClassName(ShareActivity.this, BookmarkPickerActivity.class.getName()); intent.setClassName(ShareActivity.this, BookmarkPickerActivity.class.getName());
@ -95,7 +73,7 @@ public final class ShareActivity extends Activity {
} }
}; };
private final Button.OnClickListener mClipboardListener = new Button.OnClickListener() { private final Button.OnClickListener clipboardListener = new Button.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
// Should always be true, because we grey out the clipboard button in onResume() if it's empty // Should always be true, because we grey out the clipboard button in onResume() if it's empty
@ -109,6 +87,33 @@ public final class ShareActivity extends Activity {
} }
}; };
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.share);
Button mContactButton = (Button) findViewById(R.id.contact_button);
mContactButton.setOnClickListener(contactListener);
Button mBookmarkButton = (Button) findViewById(R.id.bookmark_button);
mBookmarkButton.setOnClickListener(bookmarkListener);
clipboardButton = (Button) findViewById(R.id.clipboard_button);
clipboardButton.setOnClickListener(clipboardListener);
}
@Override
protected void onResume() {
super.onResume();
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
if (clipboard.hasText()) {
clipboardButton.setEnabled(true);
clipboardButton.setText(R.string.button_share_clipboard);
} else {
clipboardButton.setEnabled(false);
clipboardButton.setText(R.string.button_clipboard_empty);
}
}
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) { public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
@ -213,5 +218,4 @@ public final class ShareActivity extends Activity {
} }
return data; return data;
} }
} }

View file

@ -28,34 +28,35 @@ import android.view.View;
/** /**
* This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial * This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
* transparency outside it, as well as the laser scanner animation and result points. * transparency outside it, as well as the laser scanner animation and result points.
*
* @author dswitkin@google.com (Daniel Switkin)
*/ */
public final class ViewfinderView extends View { public final class ViewfinderView extends View {
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64}; private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
private static final long ANIMATION_DELAY = 100L; private static final long ANIMATION_DELAY = 100L;
private final Paint mPaint; private final Paint paint;
private final Rect mBox; private final Rect box;
private Bitmap mResultBitmap; private Bitmap resultBitmap;
private final int mMaskColor; private final int maskColor;
private final int mResultColor; private final int resultColor;
private final int mFrameColor; private final int frameColor;
private final int mLaserColor; private final int laserColor;
private int mScannerAlpha; private int scannerAlpha;
// This constructor is used when the class is built from an XML resource. // This constructor is used when the class is built from an XML resource.
public ViewfinderView(Context context, AttributeSet attrs) { public ViewfinderView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
// Initialize these once for performance rather than calling them every time in onDraw(). // Initialize these once for performance rather than calling them every time in onDraw().
mPaint = new Paint(); paint = new Paint();
mBox = new Rect(); box = new Rect();
Resources resources = getResources(); Resources resources = getResources();
mMaskColor = resources.getColor(R.color.viewfinder_mask); maskColor = resources.getColor(R.color.viewfinder_mask);
mResultColor = resources.getColor(R.color.result_view); resultColor = resources.getColor(R.color.result_view);
mFrameColor = resources.getColor(R.color.viewfinder_frame); frameColor = resources.getColor(R.color.viewfinder_frame);
mLaserColor = resources.getColor(R.color.viewfinder_laser); laserColor = resources.getColor(R.color.viewfinder_laser);
mScannerAlpha = 0; scannerAlpha = 0;
} }
@Override @Override
@ -65,48 +66,48 @@ public final class ViewfinderView extends View {
int height = canvas.getHeight(); int height = canvas.getHeight();
// Draw the exterior (i.e. outside the framing rect) darkened // Draw the exterior (i.e. outside the framing rect) darkened
mPaint.setColor(mResultBitmap != null ? mResultColor : mMaskColor); paint.setColor(resultBitmap != null ? resultColor : maskColor);
mBox.set(0, 0, width, frame.top); box.set(0, 0, width, frame.top);
canvas.drawRect(mBox, mPaint); canvas.drawRect(box, paint);
mBox.set(0, frame.top, frame.left, frame.bottom + 1); box.set(0, frame.top, frame.left, frame.bottom + 1);
canvas.drawRect(mBox, mPaint); canvas.drawRect(box, paint);
mBox.set(frame.right + 1, frame.top, width, frame.bottom + 1); box.set(frame.right + 1, frame.top, width, frame.bottom + 1);
canvas.drawRect(mBox, mPaint); canvas.drawRect(box, paint);
mBox.set(0, frame.bottom + 1, width, height); box.set(0, frame.bottom + 1, width, height);
canvas.drawRect(mBox, mPaint); canvas.drawRect(box, paint);
if (mResultBitmap != null) { if (resultBitmap != null) {
// Draw the opaque result bitmap over the scanning rectangle // Draw the opaque result bitmap over the scanning rectangle
mPaint.setAlpha(255); paint.setAlpha(255);
canvas.drawBitmap(mResultBitmap, frame.left, frame.top, mPaint); canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
} else { } else {
// Draw a two pixel solid black border inside the framing rect // Draw a two pixel solid black border inside the framing rect
mPaint.setColor(mFrameColor); paint.setColor(frameColor);
mBox.set(frame.left, frame.top, frame.right + 1, frame.top + 2); box.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
canvas.drawRect(mBox, mPaint); canvas.drawRect(box, paint);
mBox.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1); box.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
canvas.drawRect(mBox, mPaint); canvas.drawRect(box, paint);
mBox.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1); box.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
canvas.drawRect(mBox, mPaint); canvas.drawRect(box, paint);
mBox.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1); box.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
canvas.drawRect(mBox, mPaint); canvas.drawRect(box, paint);
// Draw a red "laser scanner" line through the middle to show decoding is active // Draw a red "laser scanner" line through the middle to show decoding is active
mPaint.setColor(mLaserColor); paint.setColor(laserColor);
mPaint.setAlpha(SCANNER_ALPHA[mScannerAlpha]); paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
mScannerAlpha = (mScannerAlpha + 1) % SCANNER_ALPHA.length; scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
int middle = frame.height() / 2 + frame.top; int middle = frame.height() / 2 + frame.top;
mBox.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2); box.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
canvas.drawRect(mBox, mPaint); canvas.drawRect(box, paint);
// Request another update at the animation interval, but only repaint the laser line, // Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask. // not the entire viewfinder mask.
postInvalidateDelayed(ANIMATION_DELAY, mBox.left, mBox.top, mBox.right, mBox.bottom); postInvalidateDelayed(ANIMATION_DELAY, box.left, box.top, box.right, box.bottom);
} }
} }
public void drawViewfinder() { public void drawViewfinder() {
mResultBitmap = null; resultBitmap = null;
invalidate(); invalidate();
} }
@ -116,8 +117,7 @@ public final class ViewfinderView extends View {
* @param barcode An image of the decoded barcode. * @param barcode An image of the decoded barcode.
*/ */
public void drawResultBitmap(Bitmap barcode) { public void drawResultBitmap(Bitmap barcode) {
mResultBitmap = barcode; resultBitmap = barcode;
invalidate(); invalidate();
} }
} }

View file

@ -16,34 +16,39 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import android.app.Activity;
import android.telephony.PhoneNumberUtils;
import android.text.SpannableString;
import android.text.Spannable;
import android.text.style.StyleSpan;
import com.google.zxing.client.android.R; import com.google.zxing.client.android.R;
import com.google.zxing.client.result.AddressBookParsedResult; import com.google.zxing.client.result.AddressBookParsedResult;
import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResult;
import android.app.Activity;
import android.telephony.PhoneNumberUtils;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.StyleSpan;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParsePosition; import java.text.ParsePosition;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
/**
* Handles address book entries.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class AddressBookResultHandler extends ResultHandler { public final class AddressBookResultHandler extends ResultHandler {
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd"); private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
private final boolean[] mFields; private final boolean[] fields;
private int mButtonCount; private int buttonCount;
// This takes all the work out of figuring out which buttons/actions should be in which // This takes all the work out of figuring out which buttons/actions should be in which
// positions, based on which fields are present in this barcode. // positions, based on which fields are present in this barcode.
private int mapIndexToAction(int index) { private int mapIndexToAction(int index) {
if (index < mButtonCount) { if (index < buttonCount) {
int count = -1; int count = -1;
for (int x = 0; x < MAX_BUTTON_COUNT; x++) { for (int x = 0; x < MAX_BUTTON_COUNT; x++) {
if (mFields[x]) { if (fields[x]) {
count++; count++;
} }
if (count == index) { if (count == index) {
@ -64,23 +69,23 @@ public final class AddressBookResultHandler extends ResultHandler {
String[] emails = addressResult.getEmails(); String[] emails = addressResult.getEmails();
boolean hasEmailAddress = emails != null && emails.length > 0; boolean hasEmailAddress = emails != null && emails.length > 0;
mFields = new boolean[MAX_BUTTON_COUNT]; fields = new boolean[MAX_BUTTON_COUNT];
mFields[0] = true; // Add contact is always available fields[0] = true; // Add contact is always available
mFields[1] = hasAddress; fields[1] = hasAddress;
mFields[2] = hasPhoneNumber; fields[2] = hasPhoneNumber;
mFields[3] = hasEmailAddress; fields[3] = hasEmailAddress;
mButtonCount = 0; buttonCount = 0;
for (int x = 0; x < MAX_BUTTON_COUNT; x++) { for (int x = 0; x < MAX_BUTTON_COUNT; x++) {
if (mFields[x]) { if (fields[x]) {
mButtonCount++; buttonCount++;
} }
} }
} }
@Override @Override
public int getButtonCount() { public int getButtonCount() {
return mButtonCount; return buttonCount;
} }
@Override @Override
@ -102,7 +107,7 @@ public final class AddressBookResultHandler extends ResultHandler {
@Override @Override
public void handleButtonPress(int index) { public void handleButtonPress(int index) {
AddressBookParsedResult addressResult = (AddressBookParsedResult) mResult; AddressBookParsedResult addressResult = (AddressBookParsedResult) result;
int action = mapIndexToAction(index); int action = mapIndexToAction(index);
switch (action) { switch (action) {
case 0: case 0:
@ -130,7 +135,7 @@ public final class AddressBookResultHandler extends ResultHandler {
// Overriden so we can hyphenate phone numbers, format birthdays, and bold the name. // Overriden so we can hyphenate phone numbers, format birthdays, and bold the name.
@Override @Override
public CharSequence getDisplayContents() { public CharSequence getDisplayContents() {
AddressBookParsedResult result = (AddressBookParsedResult) mResult; AddressBookParsedResult result = (AddressBookParsedResult) this.result;
StringBuffer contents = new StringBuffer(); StringBuffer contents = new StringBuffer();
ParsedResult.maybeAppend(result.getNames(), contents); ParsedResult.maybeAppend(result.getNames(), contents);
int namesLength = contents.length(); int namesLength = contents.length();
@ -178,5 +183,4 @@ public final class AddressBookResultHandler extends ResultHandler {
public int getDisplayTitle() { public int getDisplayTitle() {
return R.string.result_address_book; return R.string.result_address_book;
} }
} }

View file

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

View file

@ -16,11 +16,12 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import android.app.Activity;
import com.google.zxing.client.android.R; import com.google.zxing.client.android.R;
import com.google.zxing.client.result.CalendarParsedResult; import com.google.zxing.client.result.CalendarParsedResult;
import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResult;
import android.app.Activity;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParsePosition; import java.text.ParsePosition;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@ -28,12 +29,16 @@ import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
/**
* Handles calendar entries encoded in QR Codes.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class CalendarResultHandler extends ResultHandler { public final class CalendarResultHandler extends ResultHandler {
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd"); private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
private static final int[] mButtons = { private static final int[] buttons = {
R.string.button_add_calendar R.string.button_add_calendar
}; };
@ -43,17 +48,17 @@ public final class CalendarResultHandler extends ResultHandler {
@Override @Override
public int getButtonCount() { public int getButtonCount() {
return mButtons.length; return buttons.length;
} }
@Override @Override
public int getButtonText(int index) { public int getButtonText(int index) {
return mButtons[index]; return buttons[index];
} }
@Override @Override
public void handleButtonPress(int index) { public void handleButtonPress(int index) {
CalendarParsedResult calendarResult = (CalendarParsedResult) mResult; CalendarParsedResult calendarResult = (CalendarParsedResult) result;
switch (index) { switch (index) {
case 0: case 0:
addCalendarEvent(calendarResult.getSummary(), calendarResult.getStart(), addCalendarEvent(calendarResult.getSummary(), calendarResult.getStart(),
@ -64,7 +69,7 @@ public final class CalendarResultHandler extends ResultHandler {
@Override @Override
public CharSequence getDisplayContents() { public CharSequence getDisplayContents() {
CalendarParsedResult calResult = (CalendarParsedResult) mResult; CalendarParsedResult calResult = (CalendarParsedResult) result;
StringBuffer result = new StringBuffer(); StringBuffer result = new StringBuffer();
ParsedResult.maybeAppend(calResult.getSummary(), result); ParsedResult.maybeAppend(calResult.getSummary(), result);
appendTime(calResult.getStart(), result); appendTime(calResult.getStart(), result);
@ -110,5 +115,4 @@ public final class CalendarResultHandler extends ResultHandler {
public int getDisplayTitle() { public int getDisplayTitle() {
return R.string.result_calendar; return R.string.result_calendar;
} }
} }

View file

@ -16,14 +16,19 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import android.app.Activity;
import com.google.zxing.client.android.R; import com.google.zxing.client.android.R;
import com.google.zxing.client.result.EmailAddressParsedResult; import com.google.zxing.client.result.EmailAddressParsedResult;
import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResult;
public final class EmailAddressResultHandler extends ResultHandler { import android.app.Activity;
private static final int[] mButtons = { /**
* Handles email addresses.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class EmailAddressResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_email, R.string.button_email,
R.string.button_add_contact R.string.button_add_contact
}; };
@ -34,17 +39,17 @@ public final class EmailAddressResultHandler extends ResultHandler {
@Override @Override
public int getButtonCount() { public int getButtonCount() {
return mButtons.length; return buttons.length;
} }
@Override @Override
public int getButtonText(int index) { public int getButtonText(int index) {
return mButtons[index]; return buttons[index];
} }
@Override @Override
public void handleButtonPress(int index) { public void handleButtonPress(int index) {
EmailAddressParsedResult emailResult = (EmailAddressParsedResult) mResult; EmailAddressParsedResult emailResult = (EmailAddressParsedResult) result;
switch (index) { switch (index) {
case 0: case 0:
sendEmailFromUri(emailResult.getMailtoURI(), null, null); sendEmailFromUri(emailResult.getMailtoURI(), null, null);
@ -61,5 +66,4 @@ public final class EmailAddressResultHandler extends ResultHandler {
public int getDisplayTitle() { public int getDisplayTitle() {
return R.string.result_email_address; return R.string.result_email_address;
} }
} }

View file

@ -16,14 +16,19 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import android.app.Activity;
import com.google.zxing.client.android.R; import com.google.zxing.client.android.R;
import com.google.zxing.client.result.GeoParsedResult; import com.google.zxing.client.result.GeoParsedResult;
import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResult;
public final class GeoResultHandler extends ResultHandler { import android.app.Activity;
private static final int[] mButtons = { /**
* Handles geographic coordinates (typically encoded as geo: URLs).
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class GeoResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_show_map, R.string.button_show_map,
R.string.button_get_directions R.string.button_get_directions
}; };
@ -34,17 +39,17 @@ public final class GeoResultHandler extends ResultHandler {
@Override @Override
public int getButtonCount() { public int getButtonCount() {
return mButtons.length; return buttons.length;
} }
@Override @Override
public int getButtonText(int index) { public int getButtonText(int index) {
return mButtons[index]; return buttons[index];
} }
@Override @Override
public void handleButtonPress(int index) { public void handleButtonPress(int index) {
GeoParsedResult geoResult = (GeoParsedResult) mResult; GeoParsedResult geoResult = (GeoParsedResult) result;
switch (index) { switch (index) {
case 0: case 0:
openMap(geoResult.getGeoURI()); openMap(geoResult.getGeoURI());
@ -59,5 +64,4 @@ public final class GeoResultHandler extends ResultHandler {
public int getDisplayTitle() { public int getDisplayTitle() {
return R.string.result_geo; return R.string.result_geo;
} }
} }

View file

@ -16,44 +16,50 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import android.app.Activity;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.google.zxing.client.android.R;
import com.google.zxing.client.android.PreferencesActivity; import com.google.zxing.client.android.PreferencesActivity;
import com.google.zxing.client.android.R;
import com.google.zxing.client.result.ISBNParsedResult; import com.google.zxing.client.result.ISBNParsedResult;
import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResult;
public final class ISBNResultHandler extends ResultHandler { import android.app.Activity;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
private static final int[] mButtons = { /**
* Handles books encoded by their ISBN values.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ISBNResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_product_search, R.string.button_product_search,
R.string.button_book_search, R.string.button_book_search,
R.string.button_search_book_contents, R.string.button_search_book_contents,
R.string.button_custom_product_search, R.string.button_custom_product_search,
}; };
private final String mCustomProductSearch; private final String customProductSearch;
public ISBNResultHandler(Activity activity, ParsedResult result) { public ISBNResultHandler(Activity activity, ParsedResult result) {
super(activity, result); super(activity, result);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
mCustomProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null); customProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null);
} }
@Override @Override
public int getButtonCount() { public int getButtonCount() {
return mCustomProductSearch != null && mCustomProductSearch.length() > 0 ? mButtons.length : mButtons.length - 1; return customProductSearch != null && customProductSearch.length() > 0 ? buttons.length : buttons
.length - 1;
} }
@Override @Override
public int getButtonText(int index) { public int getButtonText(int index) {
return mButtons[index]; return buttons[index];
} }
@Override @Override
public void handleButtonPress(int index) { public void handleButtonPress(int index) {
ISBNParsedResult isbnResult = (ISBNParsedResult) mResult; ISBNParsedResult isbnResult = (ISBNParsedResult) result;
switch (index) { switch (index) {
case 0: case 0:
openProductSearch(isbnResult.getISBN()); openProductSearch(isbnResult.getISBN());
@ -65,7 +71,7 @@ public final class ISBNResultHandler extends ResultHandler {
searchBookContents(isbnResult.getISBN()); searchBookContents(isbnResult.getISBN());
break; break;
case 3: case 3:
String url = mCustomProductSearch.replace("%s", isbnResult.getISBN()); String url = customProductSearch.replace("%s", isbnResult.getISBN());
openURL(url); openURL(url);
break; break;
} }
@ -75,5 +81,4 @@ public final class ISBNResultHandler extends ResultHandler {
public int getDisplayTitle() { public int getDisplayTitle() {
return R.string.result_isbn; return R.string.result_isbn;
} }
} }

View file

@ -16,43 +16,48 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import android.app.Activity;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.google.zxing.client.android.R;
import com.google.zxing.client.android.PreferencesActivity; import com.google.zxing.client.android.PreferencesActivity;
import com.google.zxing.client.android.R;
import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ProductParsedResult; import com.google.zxing.client.result.ProductParsedResult;
public final class ProductResultHandler extends ResultHandler { import android.app.Activity;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
private static final int[] mButtons = { /**
* Handles generic products which are not books.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ProductResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_product_search, R.string.button_product_search,
R.string.button_web_search, R.string.button_web_search,
R.string.button_custom_product_search, R.string.button_custom_product_search,
}; };
private final String mCustomProductSearch; private final String customProductSearch;
public ProductResultHandler(Activity activity, ParsedResult result) { public ProductResultHandler(Activity activity, ParsedResult result) {
super(activity, result); super(activity, result);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
mCustomProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null); customProductSearch = prefs.getString(PreferencesActivity.KEY_CUSTOM_PRODUCT_SEARCH, null);
} }
@Override @Override
public int getButtonCount() { public int getButtonCount() {
return mCustomProductSearch != null ? mButtons.length : mButtons.length - 1; return customProductSearch != null ? buttons.length : buttons.length - 1;
} }
@Override @Override
public int getButtonText(int index) { public int getButtonText(int index) {
return mButtons[index]; return buttons[index];
} }
@Override @Override
public void handleButtonPress(int index) { public void handleButtonPress(int index) {
ProductParsedResult productResult = (ProductParsedResult) mResult; ProductParsedResult productResult = (ProductParsedResult) result;
switch (index) { switch (index) {
case 0: case 0:
openProductSearch(productResult.getNormalizedProductID()); openProductSearch(productResult.getNormalizedProductID());
@ -61,7 +66,7 @@ public final class ProductResultHandler extends ResultHandler {
webSearch(productResult.getNormalizedProductID()); webSearch(productResult.getNormalizedProductID());
break; break;
case 2: case 2:
String url = mCustomProductSearch.replace("%s", productResult.getNormalizedProductID()); String url = customProductSearch.replace("%s", productResult.getNormalizedProductID());
openURL(url); openURL(url);
break; break;
} }
@ -71,5 +76,4 @@ public final class ProductResultHandler extends ResultHandler {
public int getDisplayTitle() { public int getDisplayTitle() {
return R.string.result_product; return R.string.result_product;
} }
} }

View file

@ -22,19 +22,19 @@ import android.widget.Button;
/** /**
* Handles the result of barcode decoding in the context of the Android platform, by dispatching the * Handles the result of barcode decoding in the context of the Android platform, by dispatching the
* proper intents to open other activities like GMail, Maps, etc. * proper intents to open other activities like GMail, Maps, etc.
*
* @author dswitkin@google.com (Daniel Switkin)
*/ */
public final class ResultButtonListener implements Button.OnClickListener { public final class ResultButtonListener implements Button.OnClickListener {
final ResultHandler resultHandler;
final ResultHandler mResultHandler; final int index;
final int mIndex;
public ResultButtonListener(ResultHandler resultHandler, int index) { public ResultButtonListener(ResultHandler resultHandler, int index) {
mResultHandler = resultHandler; this.resultHandler = resultHandler;
mIndex = index; this.index = index;
} }
public void onClick(View view) { public void onClick(View view) {
mResultHandler.handleButtonPress(mIndex); resultHandler.handleButtonPress(index);
} }
} }

View file

@ -16,40 +16,50 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import com.google.zxing.client.android.Contents;
import com.google.zxing.client.android.Intents;
import com.google.zxing.client.android.LocaleManager;
import com.google.zxing.client.android.R;
import com.google.zxing.client.android.SearchBookContentsActivity;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ParsedResultType;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.provider.Contacts; import android.provider.Contacts;
import com.google.zxing.client.android.Intents;
import com.google.zxing.client.android.R;
import com.google.zxing.client.android.SearchBookContentsActivity;
import com.google.zxing.client.android.LocaleManager;
import com.google.zxing.client.android.Contents;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ParsedResultType;
import java.text.DateFormat;
import java.text.ParsePosition; import java.text.ParsePosition;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.text.DateFormat;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
/**
* A base class for the Android-specific barcode handlers. These allow the app to polymorphically
* suggest the appropriate actions for each data type.
*
* This class also contains a bunch of utility methods to take common actions like opening a URL.
* They could easily be moved into a helper object, but it can't be static because the Activity
* instance is needed to launch an intent.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public abstract class ResultHandler { public abstract class ResultHandler {
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd"); private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); private static final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
public static final int MAX_BUTTON_COUNT = 4; public static final int MAX_BUTTON_COUNT = 4;
protected final ParsedResult mResult; protected final ParsedResult result;
private final Activity mActivity; private final Activity activity;
protected ResultHandler(Activity activity, ParsedResult result) { protected ResultHandler(Activity activity, ParsedResult result) {
mResult = result; this.result = result;
mActivity = activity; this.activity = activity;
} }
/** /**
@ -81,7 +91,7 @@ public abstract class ResultHandler {
* @return The text to be displayed. * @return The text to be displayed.
*/ */
public CharSequence getDisplayContents() { public CharSequence getDisplayContents() {
String contents = mResult.getDisplayResult(); String contents = result.getDisplayResult();
return contents.replace("\r", ""); return contents.replace("\r", "");
} }
@ -98,7 +108,7 @@ public abstract class ResultHandler {
* @return The parsed type, e.g. URI or ISBN * @return The parsed type, e.g. URI or ISBN
*/ */
public final ParsedResultType getType() { public final ParsedResultType getType() {
return mResult.getType(); return result.getType();
} }
/** /**
@ -171,7 +181,7 @@ public abstract class ResultHandler {
} }
public final void shareByEmail(String contents) { public final void shareByEmail(String contents) {
sendEmailFromUri("mailto:", mActivity.getString(R.string.msg_share_subject_line), contents); sendEmailFromUri("mailto:", activity.getString(R.string.msg_share_subject_line), contents);
} }
public final void sendEmail(String address, String subject, String body) { public final void sendEmail(String address, String subject, String body) {
@ -188,7 +198,7 @@ public abstract class ResultHandler {
} }
public final void shareBySMS(String contents) { public final void shareBySMS(String contents) {
sendSMSFromUri("smsto:", mActivity.getString(R.string.msg_share_subject_line) + ":\n" + sendSMSFromUri("smsto:", activity.getString(R.string.msg_share_subject_line) + ":\n" +
contents); contents);
} }
@ -212,7 +222,7 @@ public abstract class ResultHandler {
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri)); Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri));
// The Messaging app needs to see a valid subject or else it will treat this an an SMS. // The Messaging app needs to see a valid subject or else it will treat this an an SMS.
if (subject == null || subject.length() == 0) { if (subject == null || subject.length() == 0) {
putExtra(intent, "subject", mActivity.getString(R.string.msg_default_mms_subject)); putExtra(intent, "subject", activity.getString(R.string.msg_default_mms_subject));
} else { } else {
putExtra(intent, "subject", subject); putExtra(intent, "subject", subject);
} }
@ -267,7 +277,7 @@ public abstract class ResultHandler {
public final void searchBookContents(String isbn) { public final void searchBookContents(String isbn) {
Intent intent = new Intent(Intents.SearchBookContents.ACTION); Intent intent = new Intent(Intents.SearchBookContents.ACTION);
intent.setClassName(mActivity, SearchBookContentsActivity.class.getName()); intent.setClassName(activity, SearchBookContentsActivity.class.getName());
putExtra(intent, Intents.SearchBookContents.ISBN, isbn); putExtra(intent, Intents.SearchBookContents.ISBN, isbn);
launchIntent(intent); launchIntent(intent);
} }
@ -285,11 +295,11 @@ public abstract class ResultHandler {
private void launchIntent(Intent intent) { private void launchIntent(Intent intent) {
if (intent != null) { if (intent != null) {
try { try {
mActivity.startActivity(intent); activity.startActivity(intent);
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(mActivity.getString(R.string.app_name)); builder.setTitle(activity.getString(R.string.app_name));
builder.setMessage(mActivity.getString(R.string.msg_intent_failed)); builder.setMessage(activity.getString(R.string.msg_intent_failed));
builder.setPositiveButton(R.string.button_ok, null); builder.setPositiveButton(R.string.button_ok, null);
builder.show(); builder.show();
} }
@ -301,5 +311,4 @@ public abstract class ResultHandler {
intent.putExtra(key, value); intent.putExtra(key, value);
} }
} }
} }

View file

@ -16,14 +16,19 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import android.app.Activity;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ParsedResultType; import com.google.zxing.client.result.ParsedResultType;
import com.google.zxing.client.result.ResultParser; import com.google.zxing.client.result.ResultParser;
public final class ResultHandlerFactory { import android.app.Activity;
/**
* Manufactures Android-specific handlers based on the barcode content's type.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ResultHandlerFactory {
private ResultHandlerFactory() { private ResultHandlerFactory() {
} }
@ -57,22 +62,6 @@ public final class ResultHandlerFactory {
} }
private static ParsedResult parseResult(Result rawResult) { private static ParsedResult parseResult(Result rawResult) {
ParsedResult result = ResultParser.parseResult(rawResult); return ResultParser.parseResult(rawResult);
// Disabled for now. To reactivate, create an AndroidIntentResultHandler.
// if (result.getType().equals(ParsedResultType.TEXT)) {
// String rawText = rawResult.getText();
// AndroidIntentParsedResult androidResult = AndroidIntentParsedResult.parse(rawText);
// if (androidResult != null) {
// Intent intent = androidResult.getIntent();
// if (!Intent.ACTION_VIEW.equals(intent.getAction())) {
// // For now, don't take anything that just parses as a View action. A lot
// // of things are accepted as a View action by default.
// result = androidResult;
// }
// }
// }
return result;
} }
} }

View file

@ -16,15 +16,20 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import android.app.Activity;
import android.telephony.PhoneNumberUtils;
import com.google.zxing.client.android.R; import com.google.zxing.client.android.R;
import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.SMSParsedResult; import com.google.zxing.client.result.SMSParsedResult;
public final class SMSResultHandler extends ResultHandler { import android.app.Activity;
import android.telephony.PhoneNumberUtils;
private static final int[] mButtons = { /**
* Handles SMS addresses, offering a choice of composing a new SMS or MMS message.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class SMSResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_sms, R.string.button_sms,
R.string.button_mms R.string.button_mms
}; };
@ -35,17 +40,17 @@ public final class SMSResultHandler extends ResultHandler {
@Override @Override
public int getButtonCount() { public int getButtonCount() {
return mButtons.length; return buttons.length;
} }
@Override @Override
public int getButtonText(int index) { public int getButtonText(int index) {
return mButtons[index]; return buttons[index];
} }
@Override @Override
public void handleButtonPress(int index) { public void handleButtonPress(int index) {
SMSParsedResult smsResult = (SMSParsedResult) mResult; SMSParsedResult smsResult = (SMSParsedResult) result;
switch (index) { switch (index) {
case 0: case 0:
sendSMS(smsResult.getNumber(), smsResult.getBody()); sendSMS(smsResult.getNumber(), smsResult.getBody());
@ -58,7 +63,7 @@ public final class SMSResultHandler extends ResultHandler {
@Override @Override
public CharSequence getDisplayContents() { public CharSequence getDisplayContents() {
SMSParsedResult smsResult = (SMSParsedResult) mResult; SMSParsedResult smsResult = (SMSParsedResult) result;
StringBuffer contents = new StringBuffer(); StringBuffer contents = new StringBuffer();
ParsedResult.maybeAppend(PhoneNumberUtils.formatNumber(smsResult.getNumber()), contents); ParsedResult.maybeAppend(PhoneNumberUtils.formatNumber(smsResult.getNumber()), contents);
ParsedResult.maybeAppend(smsResult.getVia(), contents); ParsedResult.maybeAppend(smsResult.getVia(), contents);
@ -72,5 +77,4 @@ public final class SMSResultHandler extends ResultHandler {
public int getDisplayTitle() { public int getDisplayTitle() {
return R.string.result_sms; return R.string.result_sms;
} }
} }

View file

@ -16,15 +16,20 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import android.app.Activity;
import android.telephony.PhoneNumberUtils;
import com.google.zxing.client.android.R; import com.google.zxing.client.android.R;
import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.TelParsedResult; import com.google.zxing.client.result.TelParsedResult;
public final class TelResultHandler extends ResultHandler { import android.app.Activity;
import android.telephony.PhoneNumberUtils;
private static final int[] mButtons = { /**
* Offers relevant actions for telephone numbers.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class TelResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_dial, R.string.button_dial,
R.string.button_add_contact R.string.button_add_contact
}; };
@ -35,17 +40,17 @@ public final class TelResultHandler extends ResultHandler {
@Override @Override
public int getButtonCount() { public int getButtonCount() {
return mButtons.length; return buttons.length;
} }
@Override @Override
public int getButtonText(int index) { public int getButtonText(int index) {
return mButtons[index]; return buttons[index];
} }
@Override @Override
public void handleButtonPress(int index) { public void handleButtonPress(int index) {
TelParsedResult telResult = (TelParsedResult) mResult; TelParsedResult telResult = (TelParsedResult) result;
switch (index) { switch (index) {
case 0: case 0:
dialPhoneFromUri(telResult.getTelURI()); dialPhoneFromUri(telResult.getTelURI());
@ -61,7 +66,7 @@ public final class TelResultHandler extends ResultHandler {
// Overriden so we can take advantage of Android's phone number hyphenation routines. // Overriden so we can take advantage of Android's phone number hyphenation routines.
@Override @Override
public CharSequence getDisplayContents() { public CharSequence getDisplayContents() {
String contents = mResult.getDisplayResult(); String contents = result.getDisplayResult();
contents = contents.replace("\r", ""); contents = contents.replace("\r", "");
return PhoneNumberUtils.formatNumber(contents); return PhoneNumberUtils.formatNumber(contents);
} }
@ -70,5 +75,4 @@ public final class TelResultHandler extends ResultHandler {
public int getDisplayTitle() { public int getDisplayTitle() {
return R.string.result_tel; return R.string.result_tel;
} }
} }

View file

@ -16,16 +16,18 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import android.app.Activity;
import com.google.zxing.client.android.R; import com.google.zxing.client.android.R;
import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResult;
import android.app.Activity;
/** /**
* This class handles TextParsedResult as well as unknown formats. * This class handles TextParsedResult as well as unknown formats. It's the fallback handler.
*
* @author dswitkin@google.com (Daniel Switkin)
*/ */
public final class TextResultHandler extends ResultHandler { public final class TextResultHandler extends ResultHandler {
private static final int[] buttons = {
private static final int[] mButtons = {
R.string.button_web_search, R.string.button_web_search,
R.string.button_share_by_email, R.string.button_share_by_email,
R.string.button_share_by_sms R.string.button_share_by_sms
@ -37,25 +39,25 @@ public final class TextResultHandler extends ResultHandler {
@Override @Override
public int getButtonCount() { public int getButtonCount() {
return mButtons.length; return buttons.length;
} }
@Override @Override
public int getButtonText(int index) { public int getButtonText(int index) {
return mButtons[index]; return buttons[index];
} }
@Override @Override
public void handleButtonPress(int index) { public void handleButtonPress(int index) {
switch (index) { switch (index) {
case 0: case 0:
webSearch(mResult.getDisplayResult()); webSearch(result.getDisplayResult());
break; break;
case 1: case 1:
shareByEmail(mResult.getDisplayResult()); shareByEmail(result.getDisplayResult());
break; break;
case 2: case 2:
shareBySMS(mResult.getDisplayResult()); shareBySMS(result.getDisplayResult());
break; break;
} }
} }
@ -64,5 +66,4 @@ public final class TextResultHandler extends ResultHandler {
public int getDisplayTitle() { public int getDisplayTitle() {
return R.string.result_text; return R.string.result_text;
} }
} }

View file

@ -16,14 +16,19 @@
package com.google.zxing.client.android.result; package com.google.zxing.client.android.result;
import android.app.Activity;
import com.google.zxing.client.android.R; import com.google.zxing.client.android.R;
import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.URIParsedResult; import com.google.zxing.client.result.URIParsedResult;
public final class URIResultHandler extends ResultHandler { import android.app.Activity;
private static final int[] mButtons = { /**
* Offers appropriate actions for URLS.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class URIResultHandler extends ResultHandler {
private static final int[] buttons = {
R.string.button_open_browser, R.string.button_open_browser,
R.string.button_share_by_email, R.string.button_share_by_email,
R.string.button_share_by_sms R.string.button_share_by_sms
@ -35,17 +40,17 @@ public final class URIResultHandler extends ResultHandler {
@Override @Override
public int getButtonCount() { public int getButtonCount() {
return mButtons.length; return buttons.length;
} }
@Override @Override
public int getButtonText(int index) { public int getButtonText(int index) {
return mButtons[index]; return buttons[index];
} }
@Override @Override
public void handleButtonPress(int index) { public void handleButtonPress(int index) {
URIParsedResult uriResult = (URIParsedResult) mResult; URIParsedResult uriResult = (URIParsedResult) result;
switch (index) { switch (index) {
case 0: case 0:
openURL(uriResult.getURI()); openURL(uriResult.getURI());
@ -63,5 +68,4 @@ public final class URIResultHandler extends ResultHandler {
public int getDisplayTitle() { public int getDisplayTitle() {
return R.string.result_uri; return R.string.result_uri;
} }
} }