66ab2b9d71a24ddc85a39b31e956e61089178e6c
[zxing.git] / android-m3 / 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.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;
34
35 /**
36  * The barcode reader activity itself. This is loosely based on the CameraPreview
37  * example included in the Android SDK.
38  *
39  * @author dswitkin@google.com (Daniel Switkin)
40  * @author Android Team (for CameraPreview example)
41  */
42 public final class BarcodeReaderCaptureActivity extends Activity {
43
44   private CameraManager cameraManager;
45   private CameraSurfaceView surfaceView;
46   private WorkerThread workerThread;
47
48   private static final int ABOUT_ID = Menu.FIRST;
49
50   @Override
51   public void onCreate(Bundle icicle) {
52     super.onCreate(icicle);
53     requestWindowFeature(Window.FEATURE_NO_TITLE);
54
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);
60
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();
66     workerThread.start();
67
68     // TODO re-enable this when issues with Matrix.setPolyToPoly() are resolved
69     //GridSampler.setGridSampler(new AndroidGraphicsGridSampler());
70   }
71
72   @Override
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.
77     return true;
78   }
79
80   @Override
81   protected void onResume() {
82     super.onResume();
83     cameraManager.openDriver();
84     if (workerThread == null) {
85       workerThread = new WorkerThread(this, surfaceView, cameraManager, messageHandler);
86       workerThread.requestPreviewLoop();
87       workerThread.start();
88     }
89   }
90
91   @Override
92   protected void onPause() {
93     super.onPause();
94     if (workerThread != null) {
95       workerThread.requestExitAndWait();
96       workerThread = null;
97     }
98     cameraManager.closeDriver();
99   }
100
101   @Override
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();
111     } else {
112       return super.onKeyDown(keyCode, event);
113     }
114     return true;
115   }
116
117   @Override
118   public boolean onCreateOptionsMenu(Menu menu) {
119     super.onCreateOptionsMenu(menu);
120     menu.add(0, ABOUT_ID, R.string.menu_about);
121     return true;
122   }
123
124   @Override
125   public boolean onOptionsItemSelected(Menu.Item item) {
126     switch (item.getId()) {
127       case ABOUT_ID:
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);
132         break;
133     }
134     return super.onOptionsItemSelected(item);
135   }
136
137   private final Handler messageHandler = new Handler() {
138     @Override
139     public void handleMessage(Message message) {
140       switch (message.what) {
141         case R.id.decoding_succeeded_message:
142           handleDecode((Result) message.obj);
143           break;
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);
149           break;
150       }
151     }
152   };
153
154   public void restartPreview() {
155     workerThread.requestPreviewLoop();
156   }
157
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);
163     }
164
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);
176     } else {
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);
182     }
183   }
184
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;          
196         }
197       }
198     }
199     return readerResult;
200   }
201
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;
218     } else {
219       return R.string.title_barcode_detected;
220     }
221   }
222
223 }