2 * Copyright (C) 2008 Google Inc.
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.os.Bundle;
23 import android.os.Handler;
24 import android.os.Message;
25 import android.view.KeyEvent;
26 import android.view.Menu;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.view.Window;
30 import android.widget.Button;
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) {
97 if (keyCode == KeyEvent.KEYCODE_A) {
98 cameraThread.setDecodeAllMode();
99 } else if (keyCode == KeyEvent.KEYCODE_C) {
100 Message save = Message.obtain(cameraThread.handler, R.id.save);
102 } else if (keyCode == KeyEvent.KEYCODE_P) {
103 cameraManager.setUsePreviewForDecode(true);
104 } else if (keyCode == KeyEvent.KEYCODE_Q) {
105 cameraThread.setDecodeQRMode();
106 } else if (keyCode == KeyEvent.KEYCODE_S) {
107 cameraManager.setUsePreviewForDecode(false);
108 } else if (keyCode == KeyEvent.KEYCODE_T) {
109 cameraThread.toggleTracing();
110 } else if (keyCode == KeyEvent.KEYCODE_U) {
111 cameraThread.setDecode1DMode();
113 return super.onKeyDown(keyCode, event);
119 public boolean onCreateOptionsMenu(Menu menu) {
120 super.onCreateOptionsMenu(menu);
121 menu.add(0, ABOUT_ID, R.string.menu_about);
122 menu.add(0, HELP_ID, R.string.menu_help);
127 public boolean onOptionsItemSelected(Menu.Item item) {
128 Context context = getApplication();
129 switch (item.getId()) {
131 showAlert(context.getString(R.string.title_about), 0,
132 context.getString(R.string.msg_about),
133 context.getString(R.string.button_ok),
137 showAlert(context.getString(R.string.title_help), 0,
138 context.getString(R.string.msg_help),
139 context.getString(R.string.button_ok), true);
142 return super.onOptionsItemSelected(item);
145 private final Handler messageHandler = new Handler() {
147 public void handleMessage(Message message) {
148 switch (message.what) {
149 case R.id.decode_succeeded:
150 int duration = message.arg1;
151 handleDecode((Result) message.obj, duration);
153 case R.id.restart_preview:
160 public void restartPreview() {
161 Message restart = Message.obtain(cameraThread.handler, R.id.restart_preview);
162 restart.sendToTarget();
165 private void handleDecode(Result rawResult, int duration) {
166 if (!rawResult.toString().equals(lastResult)) {
167 lastResult = rawResult.toString();
169 ResultPoint[] points = rawResult.getResultPoints();
170 if (points != null && points.length > 0) {
171 surfaceView.drawResultPoints(points);
174 TextView textView = (TextView) findViewById(R.id.status_text_view);
175 ParsedReaderResult readerResult = parseReaderResult(rawResult);
176 textView.setText(readerResult.getDisplayResult() + " (" + duration + " ms)");
178 Button actionButton = (Button) findViewById(R.id.status_action_button);
179 int buttonText = getActionButtonText(readerResult.getType());
180 if (buttonText != 0) {
181 actionButton.setVisibility(View.VISIBLE);
182 actionButton.setText(buttonText);
183 ResultHandler handler = new ResultHandler(this, readerResult);
184 actionButton.setOnClickListener(handler);
185 actionButton.requestFocus();
187 actionButton.setVisibility(View.GONE);
190 // Show the green finder patterns for one second, then restart the preview
191 Message message = Message.obtain(messageHandler, R.id.restart_preview);
192 messageHandler.sendMessageDelayed(message, 1000);
198 private void resetStatusView() {
199 TextView textView = (TextView) findViewById(R.id.status_text_view);
200 textView.setText(R.string.msg_default_status);
201 Button actionButton = (Button) findViewById(R.id.status_action_button);
202 actionButton.setVisibility(View.GONE);
206 private static ParsedReaderResult parseReaderResult(Result rawResult) {
207 ParsedReaderResult readerResult = ParsedReaderResult.parseReaderResult(rawResult);
208 if (readerResult.getType().equals(ParsedReaderResultType.TEXT)) {
209 String rawText = rawResult.getText();
210 AndroidIntentParsedResult androidResult = AndroidIntentParsedResult.parse(rawText);
211 if (androidResult != null) {
212 Intent intent = androidResult.getIntent();
213 if (!Intent.VIEW_ACTION.equals(intent.getAction())) {
214 // For now, don't take anything that just parses as a View action. A lot
215 // of things are accepted as a View action by default.
216 readerResult = androidResult;
223 private static int getActionButtonText(ParsedReaderResultType type) {
225 if (type.equals(ParsedReaderResultType.ADDRESSBOOK)) {
226 buttonText = R.string.button_add_contact;
227 } else if (type.equals(ParsedReaderResultType.URI) ||
228 type.equals(ParsedReaderResultType.BOOKMARK) ||
229 type.equals(ParsedReaderResultType.URLTO)) {
230 buttonText = R.string.button_open_browser;
231 } else if (type.equals(ParsedReaderResultType.EMAIL) ||
232 type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
233 buttonText = R.string.button_email;
234 } else if (type.equals(ParsedReaderResultType.UPC)) {
235 buttonText = R.string.button_lookup_product;
236 } else if (type.equals(ParsedReaderResultType.TEL)) {
237 buttonText = R.string.button_dial;
238 } else if (type.equals(ParsedReaderResultType.GEO)) {
239 buttonText = R.string.button_show_map;