Add support for Android Intent URIs encoded in a barcode
[zxing.git] / android / src / com / google / zxing / client / android / BarcodeReaderCaptureActivity.java
1 /*
2  * Copyright (C) 2008 Google Inc.
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.google.zxing.client.android;
18
19 import android.app.Activity;
20 import android.content.Context;
21 import android.graphics.PixelFormat;
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.Window;
28 import android.view.WindowManager.LayoutParams;
29 import com.google.zxing.Result;
30 import com.google.zxing.ResultPoint;
31 import com.google.zxing.client.result.ParsedReaderResult;
32 import com.google.zxing.client.result.ParsedReaderResultType;
33
34 /**
35  * The barcode reader activity itself. This is loosely based on the CameraPreview
36  * example included in the Android SDK.
37  *
38  * @author dswitkin@google.com (Daniel Switkin)
39  * @author Android Team (for CameraPreview example)
40  */
41 public final class BarcodeReaderCaptureActivity extends Activity {
42
43   private CameraManager cameraManager;
44   private CameraSurfaceView surfaceView;
45   private WorkerThread workerThread;
46
47   private static final int ABOUT_ID = Menu.FIRST;
48
49   @Override
50   public void onCreate(Bundle icicle) {
51     super.onCreate(icicle);
52     requestWindowFeature(Window.FEATURE_NO_TITLE);
53
54     // Make sure to create a TRANSLUCENT window. This is required for SurfaceView to work.
55     // Eventually this'll be done by the system automatically.
56     getWindow().setAttributes(new LayoutParams(LayoutParams.APPLICATION_TYPE,
57         LayoutParams.NO_STATUS_BAR_FLAG));
58     getWindow().setFormat(PixelFormat.TRANSLUCENT);
59
60     cameraManager = new CameraManager(getApplication());
61     surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
62     setContentView(surfaceView);
63     workerThread = new WorkerThread(surfaceView, cameraManager, messageHandler);
64     workerThread.requestPreviewLoop();
65     workerThread.start();
66
67     // TODO re-enable this when issues with Matrix.setPolyToPoly() are resolved
68     //GridSampler.setGridSampler(new AndroidGraphicsGridSampler());
69   }
70
71   @Override
72   protected boolean isFullscreenOpaque() {
73     // Our main window is set to translucent, but we know that we will
74     // fill it with opaque data. Tell the system that so it can perform
75     // some important optimizations.
76     return true;
77   }
78
79   @Override
80   protected void onResume() {
81     super.onResume();
82     cameraManager.openDriver();
83     if (workerThread == null) {
84       workerThread = new WorkerThread(surfaceView, cameraManager, messageHandler);
85       workerThread.requestPreviewLoop();
86       workerThread.start();
87     }
88   }
89
90   @Override
91   protected void onPause() {
92     super.onPause();
93     if (workerThread != null) {
94       workerThread.requestExitAndWait();
95       workerThread = null;
96     }
97     cameraManager.closeDriver();
98   }
99
100   @Override
101   public boolean onKeyDown(int keyCode, KeyEvent event) {
102     if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
103       workerThread.requestStillAndDecode();
104       return true;
105     } else {
106       return super.onKeyDown(keyCode, event);
107     }
108   }
109
110   @Override
111   public boolean onCreateOptionsMenu(Menu menu) {
112     super.onCreateOptionsMenu(menu);
113     menu.add(0, ABOUT_ID, R.string.menu_about);
114     return true;
115   }
116
117   @Override
118   public boolean onOptionsItemSelected(Menu.Item item) {
119     switch (item.getId()) {
120       case ABOUT_ID:
121         Context context = getApplication();
122         showAlert(context.getString(R.string.title_about),
123             context.getString(R.string.msg_about),
124             context.getString(R.string.button_ok), null, true, null);
125         break;
126     }
127     return super.onOptionsItemSelected(item);
128   }
129
130   private final Handler messageHandler = new Handler() {
131     @Override
132     public void handleMessage(Message message) {
133       switch (message.what) {
134         case R.id.decoding_succeeded_message:
135           handleDecode((Result) message.obj);
136           break;
137         case R.id.decoding_failed_message:
138           Context context = getApplication();
139           showAlert(context.getString(R.string.title_no_barcode_detected),
140               context.getString(R.string.msg_no_barcode_detected),
141               context.getString(R.string.button_ok), null, true, null);
142           break;
143       }
144     }
145   };
146
147   public void restartPreview() {
148     workerThread.requestPreviewLoop();
149   }
150
151   // TODO(dswitkin): These deprecated showAlert calls need to be updated.
152   private void handleDecode(Result rawResult) {
153     ResultPoint[] points = rawResult.getResultPoints();
154     if (points != null && points.length > 0) {
155       surfaceView.drawResultPoints(points);
156     }
157
158     Context context = getApplication();
159     ParsedReaderResult readerResult = parseReaderResult(rawResult);
160     Handler handler = new ResultHandler(this, readerResult);
161     if (canBeHandled(readerResult.getType())) {
162       // Can be handled by some external app; ask if the user wants to
163       // proceed first though
164       Message yesMessage = handler.obtainMessage(R.string.button_yes);
165       Message noMessage = handler.obtainMessage(R.string.button_no);
166       showAlert(context.getString(getDialogTitleID(readerResult.getType())),
167           readerResult.getDisplayResult(), context.getString(R.string.button_yes),
168           yesMessage, context.getString(R.string.button_no), noMessage, true, noMessage);
169     } else {
170       // Just show information to user
171       Message okMessage = handler.obtainMessage(R.string.button_ok);
172       showAlert(context.getString(R.string.title_barcode_detected),
173           readerResult.getDisplayResult(), context.getString(R.string.button_ok), okMessage, null,
174           null, true, okMessage);
175     }
176   }
177
178   private static ParsedReaderResult parseReaderResult(Result rawResult) {
179     String rawText = rawResult.getText();
180     ParsedReaderResult readerResult = ParsedReaderResult.parseReaderResult(rawText);
181     if (readerResult.getType().equals(ParsedReaderResultType.TEXT)) {
182       ParsedReaderResult androidResult = AndroidIntentParsedResult.parse(rawText);
183       if (androidResult != null) {
184         readerResult = androidResult;
185       }
186     }
187     return readerResult;
188   }
189
190   private static boolean canBeHandled(ParsedReaderResultType type) {
191     return !type.equals(ParsedReaderResultType.TEXT);
192   }
193
194   private static int getDialogTitleID(ParsedReaderResultType type) {
195     if (type.equals(ParsedReaderResultType.ADDRESSBOOK)) {
196       return R.string.title_add_contact;
197     } else if (type.equals(ParsedReaderResultType.URI) ||
198                type.equals(ParsedReaderResultType.BOOKMARK) ||
199                type.equals(ParsedReaderResultType.URLTO)) {
200       return R.string.title_open_url;
201     } else if (type.equals(ParsedReaderResultType.EMAIL) ||
202                type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
203       return R.string.title_compose_email;
204     } else if (type.equals(ParsedReaderResultType.UPC)) {
205       return R.string.title_lookup_barcode;
206     } else {
207       return R.string.title_barcode_detected;
208     }
209   }
210
211 }