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.graphics.PixelFormat;
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.view.WindowManager.LayoutParams;
32 import android.widget.Button;
33 import android.widget.TextView;
34 import com.google.zxing.Result;
35 import com.google.zxing.ResultPoint;
36 import com.google.zxing.client.result.ParsedReaderResult;
37 import com.google.zxing.client.result.ParsedReaderResultType;
40 * The barcode reader activity itself. This is loosely based on the CameraPreview
41 * example included in the Android SDK.
43 * @author dswitkin@google.com (Daniel Switkin)
44 * @author Android Team (for CameraPreview example)
46 public final class BarcodeReaderCaptureActivity extends Activity {
48 private CameraManager cameraManager;
49 private CameraSurfaceView surfaceView;
50 private CameraThread cameraThread;
51 private String lastResult;
53 private static final int ABOUT_ID = Menu.FIRST;
54 private static final int HELP_ID = Menu.FIRST + 1;
57 public void onCreate(Bundle icicle) {
58 super.onCreate(icicle);
59 requestWindowFeature(Window.FEATURE_NO_TITLE);
61 // Make sure to create a TRANSLUCENT window. This is required for SurfaceView to work.
62 // Eventually this'll be done by the system automatically.
63 getWindow().setAttributes(new LayoutParams(LayoutParams.APPLICATION_TYPE,
64 LayoutParams.NO_STATUS_BAR_FLAG));
65 getWindow().setFormat(PixelFormat.TRANSLUCENT);
67 setContentView(R.layout.main);
69 cameraManager = new CameraManager(getApplication());
70 surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
71 surfaceView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
72 LayoutParams.FILL_PARENT));
74 ViewGroup previewView = (ViewGroup) findViewById(R.id.preview_view);
75 previewView.addView(surfaceView);
78 // TODO re-enable this when issues with Matrix.setPolyToPoly() are resolved
79 //GridSampler.setGridSampler(new AndroidGraphicsGridSampler());
83 protected boolean isFullscreenOpaque() {
84 // Our main window is set to translucent, but we know that we will
85 // fill it with opaque data. Tell the system that so it can perform
86 // some important optimizations.
91 protected void onResume() {
94 cameraManager.openDriver();
95 if (cameraThread == null) {
96 cameraThread = new CameraThread(this, surfaceView, cameraManager, messageHandler);
102 protected void onPause() {
104 if (cameraThread != null) {
105 cameraThread.quitSynchronously();
108 cameraManager.closeDriver();
112 public boolean onKeyDown(int keyCode, KeyEvent event) {
113 if (keyCode == KeyEvent.KEYCODE_A) {
114 cameraThread.setDecodeAllMode();
115 } else if (keyCode == KeyEvent.KEYCODE_C) {
116 Message save = Message.obtain(cameraThread.handler, R.id.save);
118 } else if (keyCode == KeyEvent.KEYCODE_P) {
119 cameraManager.setUsePreviewForDecode(true);
120 } else if (keyCode == KeyEvent.KEYCODE_Q) {
121 cameraThread.setDecodeQRMode();
122 } else if (keyCode == KeyEvent.KEYCODE_S) {
123 cameraManager.setUsePreviewForDecode(false);
124 } else if (keyCode == KeyEvent.KEYCODE_T) {
125 cameraThread.toggleTracing();
126 } else if (keyCode == KeyEvent.KEYCODE_U) {
127 cameraThread.setDecode1DMode();
129 return super.onKeyDown(keyCode, event);
135 public boolean onCreateOptionsMenu(Menu menu) {
136 super.onCreateOptionsMenu(menu);
137 menu.add(0, ABOUT_ID, R.string.menu_about);
138 menu.add(0, HELP_ID, R.string.menu_help);
143 public boolean onOptionsItemSelected(Menu.Item item) {
144 Context context = getApplication();
145 switch (item.getId()) {
147 showAlert(context.getString(R.string.title_about),
148 context.getString(R.string.msg_about),
149 context.getString(R.string.button_ok), null, true, null);
152 showAlert(context.getString(R.string.title_help),
153 context.getString(R.string.msg_help),
154 context.getString(R.string.button_ok), null, true, null);
157 return super.onOptionsItemSelected(item);
160 private final Handler messageHandler = new Handler() {
162 public void handleMessage(Message message) {
163 switch (message.what) {
164 case R.id.decode_succeeded:
165 int duration = message.arg1;
166 handleDecode((Result) message.obj, duration);
168 case R.id.restart_preview:
175 public void restartPreview() {
176 Message restart = Message.obtain(cameraThread.handler, R.id.restart_preview);
177 restart.sendToTarget();
180 private void handleDecode(Result rawResult, int duration) {
181 if (!rawResult.toString().equals(lastResult)) {
182 lastResult = rawResult.toString();
184 ResultPoint[] points = rawResult.getResultPoints();
185 if (points != null && points.length > 0) {
186 surfaceView.drawResultPoints(points);
189 TextView textView = (TextView) findViewById(R.id.status_text_view);
190 ParsedReaderResult readerResult = parseReaderResult(rawResult);
191 textView.setText(readerResult.getDisplayResult() + " (" + duration + " ms)");
193 Button actionButton = (Button) findViewById(R.id.status_action_button);
194 int buttonText = getActionButtonText(readerResult.getType());
195 if (buttonText != 0) {
196 actionButton.setVisibility(View.VISIBLE);
197 actionButton.setText(buttonText);
198 ResultHandler handler = new ResultHandler(this, readerResult);
199 actionButton.setOnClickListener(handler);
200 actionButton.requestFocus();
202 actionButton.setVisibility(View.GONE);
205 // Show the green finder patterns for one second, then restart the preview
206 Message message = Message.obtain(messageHandler, R.id.restart_preview);
207 messageHandler.sendMessageDelayed(message, 1000);
213 private void resetStatusView() {
214 TextView textView = (TextView) findViewById(R.id.status_text_view);
215 textView.setText(R.string.msg_default_status);
216 Button actionButton = (Button) findViewById(R.id.status_action_button);
217 actionButton.setVisibility(View.GONE);
221 private static ParsedReaderResult parseReaderResult(Result rawResult) {
222 ParsedReaderResult readerResult = ParsedReaderResult.parseReaderResult(rawResult);
223 if (readerResult.getType().equals(ParsedReaderResultType.TEXT)) {
224 String rawText = rawResult.getText();
225 AndroidIntentParsedResult androidResult = AndroidIntentParsedResult.parse(rawText);
226 if (androidResult != null) {
227 Intent intent = androidResult.getIntent();
228 if (!Intent.VIEW_ACTION.equals(intent.getAction())) {
229 // For now, don't take anything that just parses as a View action. A lot
230 // of things are accepted as a View action by default.
231 readerResult = androidResult;
238 private static int getActionButtonText(ParsedReaderResultType type) {
240 if (type.equals(ParsedReaderResultType.ADDRESSBOOK)) {
241 buttonText = R.string.button_add_contact;
242 } else if (type.equals(ParsedReaderResultType.URI) ||
243 type.equals(ParsedReaderResultType.BOOKMARK) ||
244 type.equals(ParsedReaderResultType.URLTO)) {
245 buttonText = R.string.button_open_browser;
246 } else if (type.equals(ParsedReaderResultType.EMAIL) ||
247 type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
248 buttonText = R.string.button_email;
249 } else if (type.equals(ParsedReaderResultType.UPC)) {
250 buttonText = R.string.button_lookup_product;
251 } else if (type.equals(ParsedReaderResultType.TEL)) {
252 buttonText = R.string.button_dial;
253 } else if (type.equals(ParsedReaderResultType.GEO)) {
254 buttonText = R.string.button_show_map;