package com.google.zxing.client.android;
-import android.util.TypedValue;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
+import com.google.zxing.ResultMetadataType;
import com.google.zxing.ResultPoint;
import com.google.zxing.client.android.camera.CameraManager;
import com.google.zxing.client.android.history.HistoryManager;
import android.content.res.AssetFileDescriptor;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.preference.PreferenceManager;
import android.text.ClipboardManager;
import android.util.Log;
-import android.view.Gravity;
+import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
+import android.widget.Toast;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Arrays;
-import java.util.List;
import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.Vector;
import java.util.regex.Pattern;
* example included in the Android SDK.
*
* @author dswitkin@google.com (Daniel Switkin)
+ * @author Sean Owen
*/
public final class CaptureActivity extends Activity implements SurfaceHolder.Callback {
private static final int ABOUT_ID = Menu.FIRST + 4;
private static final long INTENT_RESULT_DURATION = 1500L;
+ private static final long BULK_MODE_SCAN_DELAY_MS = 1000L;
private static final float BEEP_VOLUME = 0.10f;
private static final long VIBRATE_DURATION = 200L;
PRODUCT_FORMATS.add(BarcodeFormat.EAN_13);
PRODUCT_FORMATS.add(BarcodeFormat.EAN_8);
PRODUCT_FORMATS.add(BarcodeFormat.RSS14);
- ONE_D_FORMATS = new Vector<BarcodeFormat>(PRODUCT_FORMATS.size() + 3);
+ ONE_D_FORMATS = new Vector<BarcodeFormat>(PRODUCT_FORMATS.size() + 4);
ONE_D_FORMATS.addAll(PRODUCT_FORMATS);
ONE_D_FORMATS.add(BarcodeFormat.CODE_39);
ONE_D_FORMATS.add(BarcodeFormat.CODE_93);
ALL_FORMATS.addAll(QR_CODE_FORMATS);
}
+ private static final Set<ResultMetadataType> DISPLAYABLE_METADATA_TYPES;
+ static {
+ DISPLAYABLE_METADATA_TYPES = new HashSet<ResultMetadataType>(5);
+ DISPLAYABLE_METADATA_TYPES.add(ResultMetadataType.ISSUE_NUMBER);
+ DISPLAYABLE_METADATA_TYPES.add(ResultMetadataType.SUGGESTED_PRICE);
+ DISPLAYABLE_METADATA_TYPES.add(ResultMetadataType.ERROR_CORRECTION_LEVEL);
+ DISPLAYABLE_METADATA_TYPES.add(ResultMetadataType.POSSIBLE_COUNTRY);
+ }
+
private enum Source {
NATIVE_APP_INTENT,
PRODUCT_SEARCH_LINK,
private CaptureActivityHandler handler;
private ViewfinderView viewfinderView;
- private View statusView;
+ private TextView statusView;
private View resultView;
private MediaPlayer mediaPlayer;
private Result lastResult;
private String versionName;
private HistoryManager historyManager;
- private final OnCompletionListener beepListener = new BeepListener();
+ /**
+ * When the beep has finished playing, rewind to queue up another one.
+ */
+ private final OnCompletionListener beepListener = new OnCompletionListener() {
+ public void onCompletion(MediaPlayer mediaPlayer) {
+ mediaPlayer.seekTo(0);
+ }
+ };
private final DialogInterface.OnClickListener aboutListener =
new DialogInterface.OnClickListener() {
CameraManager.init(getApplication());
viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
resultView = findViewById(R.id.result_view);
- statusView = findViewById(R.id.status_view);
+ statusView = (TextView) findViewById(R.id.status_view);
handler = null;
lastResult = null;
hasSurface = false;
@Override
protected void onResume() {
super.onResume();
+ resetStatusView();
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
// Scan the formats the intent requested, and return the result to the calling activity.
source = Source.NATIVE_APP_INTENT;
decodeFormats = parseDecodeFormats(intent);
- resetStatusView();
} else if (dataString != null && dataString.contains(PRODUCT_SEARCH_URL_PREFIX) &&
dataString.contains(PRODUCT_SEARCH_URL_SUFFIX)) {
// Scan only products and send the result to mobile Product Search.
source = Source.PRODUCT_SEARCH_LINK;
sourceUrl = dataString;
decodeFormats = PRODUCT_FORMATS;
- resetStatusView();
} else if (dataString != null && dataString.startsWith(ZXING_URL)) {
// Scan formats requested in query string (all formats if none specified).
- // If a return URL is specified, send the results there. Otherwise, handle the results ourselves.
+ // If a return URL is specified, send the results there. Otherwise, handle it ourselves.
source = Source.ZXING_LINK;
sourceUrl = dataString;
Uri inputUri = Uri.parse(sourceUrl);
returnUrlTemplate = inputUri.getQueryParameter(RETURN_URL_PARAM);
decodeFormats = parseDecodeFormats(inputUri);
- resetStatusView();
} else {
// Scan all formats and handle the results ourselves (launched from Home).
source = Source.NONE;
decodeFormats = null;
- resetStatusView();
}
characterSet = intent.getStringExtra(Intents.Scan.CHARACTER_SET);
} else {
source = Source.NONE;
decodeFormats = null;
characterSet = null;
- if (lastResult == null) {
- resetStatusView();
- }
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.title_about) + versionName);
builder.setMessage(getString(R.string.msg_about) + "\n\n" + getString(R.string.zxing_url));
- builder.setIcon(R.drawable.zxing_icon);
+ builder.setIcon(R.drawable.launcher_icon);
builder.setPositiveButton(R.string.button_open_browser, aboutListener);
builder.setNegativeButton(R.string.button_cancel, null);
builder.show();
handleDecodeExternally(rawResult, barcode);
break;
case ZXING_LINK:
- if(returnUrlTemplate == null){
+ if (returnUrlTemplate == null){
handleDecodeInternally(rawResult, barcode);
} else {
handleDecodeExternally(rawResult, barcode);
}
break;
case NONE:
- handleDecodeInternally(rawResult, barcode);
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ if (prefs.getBoolean(PreferencesActivity.KEY_BULK_MODE, false)) {
+ Toast.makeText(this, R.string.msg_bulk_mode_scanned, Toast.LENGTH_SHORT).show();
+ // Wait a moment or else it will scan the same barcode continuously about 3 times
+ if (handler != null) {
+ handler.sendEmptyMessageDelayed(R.id.restart_preview, BULK_MODE_SCAN_DELAY_MS);
+ }
+ resetStatusView();
+ } else {
+ handleDecodeInternally(rawResult, barcode);
+ }
break;
}
}
paint.setColor(getResources().getColor(R.color.result_points));
if (points.length == 2) {
paint.setStrokeWidth(4.0f);
- canvas.drawLine(points[0].getX(), points[0].getY(), points[1].getX(),
- points[1].getY(), paint);
+ drawLine(canvas, paint, points[0], points[1]);
+ } else if (points.length == 4 &&
+ (rawResult.getBarcodeFormat().equals(BarcodeFormat.UPC_A)) ||
+ (rawResult.getBarcodeFormat().equals(BarcodeFormat.EAN_13))) {
+ // Hacky special case -- draw two lines, for the barcode and metadata
+ drawLine(canvas, paint, points[0], points[1]);
+ drawLine(canvas, paint, points[2], points[3]);
} else {
paint.setStrokeWidth(10.0f);
for (ResultPoint point : points) {
}
}
+ private static void drawLine(Canvas canvas, Paint paint, ResultPoint a, ResultPoint b) {
+ canvas.drawLine(a.getX(), a.getY(), b.getX(), b.getY(), paint);
+ }
+
// Put up our own UI for how to handle the decoded contents.
private void handleDecodeInternally(Result rawResult, Bitmap barcode) {
statusView.setVisibility(View.GONE);
ImageView barcodeImageView = (ImageView) findViewById(R.id.barcode_image_view);
if (barcode == null) {
- barcodeImageView.setImageResource(R.drawable.launcher_icon_large);
+ barcodeImageView.setImageBitmap(BitmapFactory.decodeResource(getResources(),
+ R.drawable.launcher_icon));
} else {
barcodeImageView.setImageBitmap(barcode);
}
- barcodeImageView.setVisibility(View.VISIBLE);
TextView formatTextView = (TextView) findViewById(R.id.format_text_view);
- formatTextView.setVisibility(View.VISIBLE);
formatTextView.setText(rawResult.getBarcodeFormat().toString());
ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult);
TextView typeTextView = (TextView) findViewById(R.id.type_text_view);
- typeTextView.setVisibility(View.VISIBLE);
typeTextView.setText(resultHandler.getType().toString());
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
String formattedTime = formatter.format(new Date(rawResult.getTimestamp()));
TextView timeTextView = (TextView) findViewById(R.id.time_text_view);
- timeTextView.setVisibility(View.VISIBLE);
timeTextView.setText(formattedTime);
+
+ TextView metaTextView = (TextView) findViewById(R.id.meta_text_view);
+ View metaTextViewLabel = findViewById(R.id.meta_text_view_label);
+ metaTextView.setVisibility(View.GONE);
+ metaTextViewLabel.setVisibility(View.GONE);
+ Map<ResultMetadataType,Object> metadata =
+ (Map<ResultMetadataType,Object>) rawResult.getResultMetadata();
+ if (metadata != null) {
+ StringBuilder metadataText = new StringBuilder(20);
+ for (Map.Entry<ResultMetadataType,Object> entry : metadata.entrySet()) {
+ if (DISPLAYABLE_METADATA_TYPES.contains(entry.getKey())) {
+ metadataText.append(entry.getValue()).append('\n');
+ }
+ }
+ if (metadataText.length() > 0) {
+ metadataText.setLength(metadataText.length() - 1);
+ metaTextView.setText(metadataText);
+ metaTextView.setVisibility(View.VISIBLE);
+ metaTextViewLabel.setVisibility(View.VISIBLE);
+ }
+ }
+
TextView contentsTextView = (TextView) findViewById(R.id.contents_text_view);
CharSequence displayContents = resultHandler.getDisplayContents();
contentsTextView.setText(displayContents);
- // Crudely scale betweeen 22 and 48 -- bigger font for shorter text
- int scaledSize = Math.max(22, 48 - displayContents.length() / 4);
+ // Crudely scale betweeen 22 and 32 -- bigger font for shorter text
+ int scaledSize = Math.max(22, 32 - displayContents.length() / 4);
contentsTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, scaledSize);
int buttonCount = resultHandler.getButtonCount();
// barcode was found (e.g. contact info) rather than the full contents, which they won't
// have time to read.
ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult);
- TextView textView = (TextView) findViewById(R.id.status_text_view);
- textView.setGravity(Gravity.CENTER);
- textView.setTextSize(18.0f);
- textView.setText(getString(resultHandler.getDisplayTitle()));
-
- statusView.setBackgroundColor(getResources().getColor(R.color.transparent));
+ statusView.setText(getString(resultHandler.getDisplayTitle()));
if (copyToClipboard) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
// Replace each occurrence of RETURN_CODE_PLACEHOLDER in the returnUrlTemplate
// with the scanned code. This allows both queries and REST-style URLs to work.
Message message = Message.obtain(handler, R.id.launch_product_query);
- message.obj = returnUrlTemplate.replace(RETURN_CODE_PLACEHOLDER, resultHandler.getDisplayContents().toString());
+ message.obj = returnUrlTemplate.replace(RETURN_CODE_PLACEHOLDER,
+ resultHandler.getDisplayContents().toString());
handler.sendMessageDelayed(message, INTENT_RESULT_DURATION);
}
}
return;
}
if (handler == null) {
- boolean beginScanning = lastResult == null;
- handler = new CaptureActivityHandler(this, decodeFormats, characterSet, beginScanning);
+ handler = new CaptureActivityHandler(this, decodeFormats, characterSet);
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.app_name));
builder.setMessage(getString(R.string.msg_camera_framework_bug));
- builder.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialogInterface, int i) {
- finish();
- }
- });
+ builder.setPositiveButton(R.string.button_ok, new FinishListener(this));
+ builder.setOnCancelListener(new FinishListener(this));
builder.show();
}
private void resetStatusView() {
resultView.setVisibility(View.GONE);
+ statusView.setText(R.string.msg_default_status);
statusView.setVisibility(View.VISIBLE);
- statusView.setBackgroundColor(getResources().getColor(R.color.status_view));
viewfinderView.setVisibility(View.VISIBLE);
-
- TextView textView = (TextView) findViewById(R.id.status_text_view);
- textView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
- textView.setTextSize(14.0f);
- textView.setText(R.string.msg_default_status);
lastResult = null;
}
public void drawViewfinder() {
viewfinderView.drawViewfinder();
}
-
- /**
- * When the beep has finished playing, rewind to queue up another one.
- */
- private static class BeepListener implements OnCompletionListener {
- public void onCompletion(MediaPlayer mediaPlayer) {
- mediaPlayer.seekTo(0);
- }
- }
}