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.media.MediaPlayer;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.Message;
27 import android.view.KeyEvent;
28 import android.view.Menu;
29 import android.view.View;
30 import android.view.ViewGroup;
31 import android.view.Window;
32 import android.view.WindowManager.LayoutParams;
33 import android.widget.Button;
34 import android.widget.TextView;
35 import com.google.zxing.Result;
36 import com.google.zxing.ResultPoint;
37 import com.google.zxing.client.result.ParsedReaderResult;
38 import com.google.zxing.client.result.ParsedReaderResultType;
41 * The barcode reader activity itself. This is loosely based on the CameraPreview
42 * example included in the Android SDK.
44 * @author dswitkin@google.com (Daniel Switkin)
45 * @author Android Team (for CameraPreview example)
47 public final class BarcodeReaderCaptureActivity extends Activity {
49 private CameraManager cameraManager;
50 private CameraSurfaceView surfaceView;
51 private CameraThread cameraThread;
52 private String lastResult;
54 private static final int ABOUT_ID = Menu.FIRST;
55 private static final int HELP_ID = Menu.FIRST + 1;
58 public void onCreate(Bundle icicle) {
59 super.onCreate(icicle);
60 requestWindowFeature(Window.FEATURE_NO_TITLE);
62 // Make sure to create a TRANSLUCENT window. This is required for SurfaceView to work.
63 // Eventually this'll be done by the system automatically.
64 getWindow().setAttributes(new LayoutParams(LayoutParams.APPLICATION_TYPE,
65 LayoutParams.NO_STATUS_BAR_FLAG));
66 getWindow().setFormat(PixelFormat.TRANSLUCENT);
68 setContentView(R.layout.main);
70 cameraManager = new CameraManager(getApplication());
71 surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
72 surfaceView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
73 LayoutParams.FILL_PARENT));
75 ViewGroup previewView = (ViewGroup) findViewById(R.id.preview_view);
76 previewView.addView(surfaceView);
79 // TODO re-enable this when issues with Matrix.setPolyToPoly() are resolved
80 //GridSampler.setGridSampler(new AndroidGraphicsGridSampler());
84 protected boolean isFullscreenOpaque() {
85 // Our main window is set to translucent, but we know that we will
86 // fill it with opaque data. Tell the system that so it can perform
87 // some important optimizations.
92 protected void onResume() {
95 cameraManager.openDriver();
96 if (cameraThread == null) {
97 cameraThread = new CameraThread(this, surfaceView, cameraManager, messageHandler);
103 protected void onPause() {
105 if (cameraThread != null) {
106 cameraThread.quitSynchronously();
109 cameraManager.closeDriver();
113 public boolean onKeyDown(int keyCode, KeyEvent event) {
114 if (keyCode == KeyEvent.KEYCODE_A) {
115 cameraThread.setDecodeAllMode();
116 } else if (keyCode == KeyEvent.KEYCODE_C) {
117 Message save = Message.obtain(cameraThread.handler, R.id.save);
119 } else if (keyCode == KeyEvent.KEYCODE_P) {
120 cameraManager.setUsePreviewForDecode(true);
121 } else if (keyCode == KeyEvent.KEYCODE_Q) {
122 cameraThread.setDecodeQRMode();
123 } else if (keyCode == KeyEvent.KEYCODE_S) {
124 cameraManager.setUsePreviewForDecode(false);
125 } else if (keyCode == KeyEvent.KEYCODE_T) {
126 cameraThread.toggleTracing();
127 } else if (keyCode == KeyEvent.KEYCODE_U) {
128 cameraThread.setDecode1DMode();
130 return super.onKeyDown(keyCode, event);
136 public boolean onCreateOptionsMenu(Menu menu) {
137 super.onCreateOptionsMenu(menu);
138 menu.add(0, ABOUT_ID, R.string.menu_about);
139 menu.add(0, HELP_ID, R.string.menu_help);
144 public boolean onOptionsItemSelected(Menu.Item item) {
145 Context context = getApplication();
146 switch (item.getId()) {
148 showAlert(context.getString(R.string.title_about),
149 context.getString(R.string.msg_about),
150 context.getString(R.string.button_ok), null, true, null);
153 showAlert(context.getString(R.string.title_help),
154 context.getString(R.string.msg_help),
155 context.getString(R.string.button_ok), null, true, null);
158 return super.onOptionsItemSelected(item);
161 private final Handler messageHandler = new Handler() {
163 public void handleMessage(Message message) {
164 switch (message.what) {
165 case R.id.decode_succeeded:
166 int duration = message.arg1;
167 handleDecode((Result) message.obj, duration);
169 case R.id.restart_preview:
176 public void restartPreview() {
177 resetStatusViewColor();
178 Message restart = Message.obtain(cameraThread.handler, R.id.restart_preview);
179 restart.sendToTarget();
182 private void handleDecode(Result rawResult, int duration) {
183 if (!rawResult.toString().equals(lastResult)) {
184 lastResult = rawResult.toString();
187 ResultPoint[] points = rawResult.getResultPoints();
188 if (points != null && points.length > 0) {
189 surfaceView.drawResultPoints(points);
192 TextView textView = (TextView) findViewById(R.id.status_text_view);
193 ParsedReaderResult readerResult = parseReaderResult(rawResult);
194 textView.setText(readerResult.getDisplayResult() + " (" + duration + " ms)");
196 Button actionButton = (Button) findViewById(R.id.status_action_button);
197 int buttonText = getActionButtonText(readerResult.getType());
198 if (buttonText != 0) {
199 actionButton.setVisibility(View.VISIBLE);
200 actionButton.setText(buttonText);
201 ResultHandler handler = new ResultHandler(this, readerResult);
202 actionButton.setOnClickListener(handler);
203 actionButton.requestFocus();
205 actionButton.setVisibility(View.GONE);
208 View statusView = findViewById(R.id.status_view);
209 statusView.setBackgroundColor(0xc000ff00);
211 // Show the green finder patterns for one second, then restart the preview
212 Message message = Message.obtain(messageHandler, R.id.restart_preview);
213 messageHandler.sendMessageDelayed(message, 1000);
219 private void playBeepSound() {
220 MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.beep);
221 mediaPlayer.prepare();
225 private void resetStatusView() {
226 resetStatusViewColor();
227 TextView textView = (TextView) findViewById(R.id.status_text_view);
228 textView.setText(R.string.msg_default_status);
229 Button actionButton = (Button) findViewById(R.id.status_action_button);
230 actionButton.setVisibility(View.GONE);
234 private void resetStatusViewColor() {
235 View statusView = findViewById(R.id.status_view);
236 statusView.setBackgroundColor(0x50000000);
239 private static ParsedReaderResult parseReaderResult(Result rawResult) {
240 ParsedReaderResult readerResult = ParsedReaderResult.parseReaderResult(rawResult);
241 if (readerResult.getType().equals(ParsedReaderResultType.TEXT)) {
242 String rawText = rawResult.getText();
243 AndroidIntentParsedResult androidResult = AndroidIntentParsedResult.parse(rawText);
244 if (androidResult != null) {
245 Intent intent = androidResult.getIntent();
246 if (!Intent.VIEW_ACTION.equals(intent.getAction())) {
247 // For now, don't take anything that just parses as a View action. A lot
248 // of things are accepted as a View action by default.
249 readerResult = androidResult;
256 private static int getActionButtonText(ParsedReaderResultType type) {
258 if (type.equals(ParsedReaderResultType.ADDRESSBOOK)) {
259 buttonText = R.string.button_add_contact;
260 } else if (type.equals(ParsedReaderResultType.URI) ||
261 type.equals(ParsedReaderResultType.BOOKMARK) ||
262 type.equals(ParsedReaderResultType.URLTO)) {
263 buttonText = R.string.button_open_browser;
264 } else if (type.equals(ParsedReaderResultType.EMAIL) ||
265 type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
266 buttonText = R.string.button_email;
267 } else if (type.equals(ParsedReaderResultType.UPC)) {
268 buttonText = R.string.button_lookup_product;
269 } else if (type.equals(ParsedReaderResultType.TEL)) {
270 buttonText = R.string.button_dial;
271 } else if (type.equals(ParsedReaderResultType.GEO)) {
272 buttonText = R.string.button_show_map;