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.Window;
29 import android.view.WindowManager.LayoutParams;
30 import com.google.zxing.Result;
31 import com.google.zxing.ResultPoint;
32 import com.google.zxing.client.result.ParsedReaderResult;
33 import com.google.zxing.client.result.ParsedReaderResultType;
36 * The barcode reader activity itself. This is loosely based on the CameraPreview
37 * example included in the Android SDK.
39 * @author dswitkin@google.com (Daniel Switkin)
40 * @author Android Team (for CameraPreview example)
42 public final class BarcodeReaderCaptureActivity extends Activity {
44 private CameraManager cameraManager;
45 private CameraSurfaceView surfaceView;
46 private WorkerThread workerThread;
48 private static final int ABOUT_ID = Menu.FIRST;
51 public void onCreate(Bundle icicle) {
52 super.onCreate(icicle);
53 requestWindowFeature(Window.FEATURE_NO_TITLE);
55 // Make sure to create a TRANSLUCENT window. This is required for SurfaceView to work.
56 // Eventually this'll be done by the system automatically.
57 getWindow().setAttributes(new LayoutParams(LayoutParams.APPLICATION_TYPE,
58 LayoutParams.NO_STATUS_BAR_FLAG));
59 getWindow().setFormat(PixelFormat.TRANSLUCENT);
61 cameraManager = new CameraManager(getApplication());
62 surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
63 setContentView(surfaceView);
64 workerThread = new WorkerThread(this, surfaceView, cameraManager, messageHandler);
65 workerThread.requestPreviewLoop();
68 // TODO re-enable this when issues with Matrix.setPolyToPoly() are resolved
69 //GridSampler.setGridSampler(new AndroidGraphicsGridSampler());
73 protected boolean isFullscreenOpaque() {
74 // Our main window is set to translucent, but we know that we will
75 // fill it with opaque data. Tell the system that so it can perform
76 // some important optimizations.
81 protected void onResume() {
83 cameraManager.openDriver();
84 if (workerThread == null) {
85 workerThread = new WorkerThread(this, surfaceView, cameraManager, messageHandler);
86 workerThread.requestPreviewLoop();
92 protected void onPause() {
94 if (workerThread != null) {
95 workerThread.requestExitAndWait();
98 cameraManager.closeDriver();
102 public boolean onKeyDown(int keyCode, KeyEvent event) {
103 if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
104 workerThread.requestStillAndDecode();
105 } else if (keyCode == KeyEvent.KEYCODE_Q) {
106 workerThread.requestStillAndDecodeQR();
107 } else if (keyCode == KeyEvent.KEYCODE_U) {
108 workerThread.requestStillAndDecode1D();
109 } else if (keyCode == KeyEvent.KEYCODE_C) {
110 workerThread.requestStillAndSave();
112 return super.onKeyDown(keyCode, event);
118 public boolean onCreateOptionsMenu(Menu menu) {
119 super.onCreateOptionsMenu(menu);
120 menu.add(0, ABOUT_ID, R.string.menu_about);
125 public boolean onOptionsItemSelected(Menu.Item item) {
126 switch (item.getId()) {
128 Context context = getApplication();
129 showAlert(context.getString(R.string.title_about),
130 context.getString(R.string.msg_about),
131 context.getString(R.string.button_ok), null, true, null);
134 return super.onOptionsItemSelected(item);
137 private final Handler messageHandler = new Handler() {
139 public void handleMessage(Message message) {
140 switch (message.what) {
141 case R.id.decoding_succeeded_message:
142 handleDecode((Result) message.obj);
144 case R.id.decoding_failed_message:
145 Context context = getApplication();
146 showAlert(context.getString(R.string.title_no_barcode_detected),
147 context.getString(R.string.msg_no_barcode_detected),
148 context.getString(R.string.button_ok), null, true, null);
154 public void restartPreview() {
155 workerThread.requestPreviewLoop();
158 // TODO(dswitkin): These deprecated showAlert calls need to be updated.
159 private void handleDecode(Result rawResult) {
160 ResultPoint[] points = rawResult.getResultPoints();
161 if (points != null && points.length > 0) {
162 surfaceView.drawResultPoints(points);
165 Context context = getApplication();
166 ParsedReaderResult readerResult = parseReaderResult(rawResult);
167 ResultHandler handler = new ResultHandler(this, readerResult);
168 if (handler.getIntent() != null) {
169 // Can be handled by some external app; ask if the user wants to
170 // proceed first though
171 Message yesMessage = handler.obtainMessage(R.string.button_yes);
172 Message noMessage = handler.obtainMessage(R.string.button_no);
173 showAlert(context.getString(getDialogTitleID(readerResult.getType())),
174 readerResult.getDisplayResult(), context.getString(R.string.button_yes),
175 yesMessage, context.getString(R.string.button_no), noMessage, true, noMessage);
177 // Just show information to user
178 Message okMessage = handler.obtainMessage(R.string.button_ok);
179 showAlert(context.getString(R.string.title_barcode_detected),
180 readerResult.getDisplayResult(), context.getString(R.string.button_ok), okMessage, null,
181 null, true, okMessage);
185 private static ParsedReaderResult parseReaderResult(Result rawResult) {
186 ParsedReaderResult readerResult = ParsedReaderResult.parseReaderResult(rawResult);
187 if (readerResult.getType().equals(ParsedReaderResultType.TEXT)) {
188 String rawText = rawResult.getText();
189 AndroidIntentParsedResult androidResult = AndroidIntentParsedResult.parse(rawText);
190 if (androidResult != null) {
191 Intent intent = androidResult.getIntent();
192 if (!Intent.VIEW_ACTION.equals(intent.getAction())) {
193 // For now, don't take anything that just parses as a View action. A lot
194 // of things are accepted as a View action by default.
195 readerResult = androidResult;
202 private static int getDialogTitleID(ParsedReaderResultType type) {
203 if (type.equals(ParsedReaderResultType.ADDRESSBOOK)) {
204 return R.string.title_add_contact;
205 } else if (type.equals(ParsedReaderResultType.URI) ||
206 type.equals(ParsedReaderResultType.BOOKMARK) ||
207 type.equals(ParsedReaderResultType.URLTO)) {
208 return R.string.title_open_url;
209 } else if (type.equals(ParsedReaderResultType.EMAIL) ||
210 type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
211 return R.string.title_compose_email;
212 } else if (type.equals(ParsedReaderResultType.UPC)) {
213 return R.string.title_lookup_barcode;
214 } else if (type.equals(ParsedReaderResultType.TEL)) {
215 return R.string.title_dial;
216 } else if (type.equals(ParsedReaderResultType.GEO)) {
217 return R.string.title_view_maps;
219 return R.string.title_barcode_detected;