2 * Copyright 2008 ZXing authors
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.google.zxing.client.android;
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.media.MediaPlayer;
23 import android.os.Bundle;
24 import android.os.Handler;
25 import android.os.Message;
26 import android.view.KeyEvent;
27 import android.view.Menu;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.view.Window;
31 import android.widget.TextView;
32 import com.google.zxing.Result;
33 import com.google.zxing.ResultPoint;
34 import com.google.zxing.client.result.ParsedReaderResult;
35 import com.google.zxing.client.result.ParsedReaderResultType;
38 * The barcode reader activity itself. This is loosely based on the CameraPreview
39 * example included in the Android SDK.
41 * @author dswitkin@google.com (Daniel Switkin)
42 * @author Android Team (for CameraPreview example)
44 public final class BarcodeReaderCaptureActivity extends Activity {
46 private CameraManager cameraManager;
47 private CameraSurfaceView surfaceView;
48 private CameraThread cameraThread;
49 private String lastResult;
51 private static final int ABOUT_ID = Menu.FIRST;
52 private static final int HELP_ID = Menu.FIRST + 1;
55 public void onCreate(Bundle icicle) {
56 super.onCreate(icicle);
57 requestWindowFeature(Window.FEATURE_NO_TITLE);
59 setContentView(R.layout.main);
61 cameraManager = new CameraManager(getApplication());
62 surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
63 surfaceView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
64 ViewGroup.LayoutParams.FILL_PARENT));
66 ViewGroup previewView = (ViewGroup) findViewById(R.id.preview_view);
67 previewView.addView(surfaceView);
70 // TODO re-enable this when issues with Matrix.setPolyToPoly() are resolved
71 //GridSampler.setGridSampler(new AndroidGraphicsGridSampler());
75 protected void onResume() {
78 cameraManager.openDriver();
79 if (cameraThread == null) {
80 cameraThread = new CameraThread(this, surfaceView, cameraManager, messageHandler);
86 protected void onPause() {
88 if (cameraThread != null) {
89 cameraThread.quitSynchronously();
92 cameraManager.closeDriver();
96 public boolean onKeyDown(int keyCode, KeyEvent event) {
98 case KeyEvent.KEYCODE_A:
99 cameraThread.setDecodeAllMode();
101 case KeyEvent.KEYCODE_C:
102 Message save = Message.obtain(cameraThread.handler, R.id.save);
105 case KeyEvent.KEYCODE_P:
106 cameraManager.setUsePreviewForDecode(true);
108 case KeyEvent.KEYCODE_Q:
109 cameraThread.setDecodeQRMode();
111 case KeyEvent.KEYCODE_S:
112 cameraManager.setUsePreviewForDecode(false);
114 case KeyEvent.KEYCODE_T:
115 cameraThread.toggleTracing();
117 case KeyEvent.KEYCODE_U:
118 cameraThread.setDecode1DMode();
121 return super.onKeyDown(keyCode, event);
127 public boolean onCreateOptionsMenu(Menu menu) {
128 super.onCreateOptionsMenu(menu);
129 menu.add(0, ABOUT_ID, R.string.menu_about);
130 menu.add(0, HELP_ID, R.string.menu_help);
135 public boolean onOptionsItemSelected(Menu.Item item) {
136 Context context = getApplication();
137 switch (item.getId()) {
139 showAlert(context.getString(R.string.title_about), 0,
140 context.getString(R.string.msg_about),
141 context.getString(R.string.button_ok),
145 showAlert(context.getString(R.string.title_help), 0,
146 context.getString(R.string.msg_help),
147 context.getString(R.string.button_ok), true);
150 return super.onOptionsItemSelected(item);
153 private final Handler messageHandler = new Handler() {
155 public void handleMessage(Message message) {
156 switch (message.what) {
157 case R.id.decode_succeeded:
158 int duration = message.arg1;
159 handleDecode((Result) message.obj, duration);
161 case R.id.restart_preview:
168 void restartPreview() {
169 resetStatusViewColor();
170 Message restart = Message.obtain(cameraThread.handler, R.id.restart_preview);
171 restart.sendToTarget();
174 private void handleDecode(Result rawResult, int duration) {
175 if (!rawResult.toString().equals(lastResult)) {
176 lastResult = rawResult.toString();
179 ResultPoint[] points = rawResult.getResultPoints();
180 if (points != null && points.length > 0) {
181 surfaceView.drawResultPoints(points);
184 TextView textView = (TextView) findViewById(R.id.status_text_view);
185 ParsedReaderResult readerResult = parseReaderResult(rawResult);
186 textView.setText(readerResult.getDisplayResult() + " (" + duration + " ms)");
188 TextView actionButton = (TextView) findViewById(R.id.status_action_button);
189 int buttonText = getActionButtonText(readerResult.getType());
190 if (buttonText != 0) {
191 actionButton.setVisibility(View.VISIBLE);
192 actionButton.setText(buttonText);
193 View.OnClickListener handler = new ResultHandler(this, readerResult);
194 actionButton.setOnClickListener(handler);
195 actionButton.requestFocus();
197 actionButton.setVisibility(View.GONE);
200 View statusView = findViewById(R.id.status_view);
201 statusView.setBackgroundColor(0xc000ff00);
203 // Show the green finder patterns for one second, then restart the preview
204 Message message = Message.obtain(messageHandler, R.id.restart_preview);
205 messageHandler.sendMessageDelayed(message, 1000);
211 private void playBeepSound() {
212 MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.beep);
216 private void resetStatusView() {
217 resetStatusViewColor();
218 TextView textView = (TextView) findViewById(R.id.status_text_view);
219 textView.setText(R.string.msg_default_status);
220 View actionButton = findViewById(R.id.status_action_button);
221 actionButton.setVisibility(View.GONE);
225 private void resetStatusViewColor() {
226 View statusView = findViewById(R.id.status_view);
227 statusView.setBackgroundColor(0x50000000);
230 private static ParsedReaderResult parseReaderResult(Result rawResult) {
231 ParsedReaderResult readerResult = ParsedReaderResult.parseReaderResult(rawResult);
232 if (readerResult.getType().equals(ParsedReaderResultType.TEXT)) {
233 String rawText = rawResult.getText();
234 AndroidIntentParsedResult androidResult = AndroidIntentParsedResult.parse(rawText);
235 if (androidResult != null) {
236 Intent intent = androidResult.getIntent();
237 if (!Intent.VIEW_ACTION.equals(intent.getAction())) {
238 // For now, don't take anything that just parses as a View action. A lot
239 // of things are accepted as a View action by default.
240 readerResult = androidResult;
247 private static int getActionButtonText(ParsedReaderResultType type) {
249 if (type.equals(ParsedReaderResultType.ADDRESSBOOK)) {
250 buttonText = R.string.button_add_contact;
251 } else if (type.equals(ParsedReaderResultType.URI) ||
252 type.equals(ParsedReaderResultType.BOOKMARK) ||
253 type.equals(ParsedReaderResultType.URLTO)) {
254 buttonText = R.string.button_open_browser;
255 } else if (type.equals(ParsedReaderResultType.EMAIL) ||
256 type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
257 buttonText = R.string.button_email;
258 } else if (type.equals(ParsedReaderResultType.UPC)) {
259 buttonText = R.string.button_lookup_product;
260 } else if (type.equals(ParsedReaderResultType.TEL)) {
261 buttonText = R.string.button_dial;
262 } else if (type.equals(ParsedReaderResultType.GEO)) {
263 buttonText = R.string.button_show_map;