4d9a9bc1c9d7ba0961221d8d893254b68d692ca7
[zxing.git] / android / src / com / android / barcodes / BarcodesCaptureActivity.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.android.barcodes;
18
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.content.DialogInterface;
22 import android.content.Intent;
23 import android.content.SharedPreferences;
24 import android.content.res.AssetFileDescriptor;
25 import android.media.MediaPlayer;
26 import android.media.AudioManager;
27 import android.media.MediaPlayer.OnCompletionListener;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.os.Message;
31 import android.preference.PreferenceManager;
32 import android.view.KeyEvent;
33 import android.view.Menu;
34 import android.view.MenuItem;
35 import android.view.SurfaceHolder;
36 import android.view.SurfaceView;
37 import android.view.View;
38 import android.view.Window;
39 import android.view.WindowManager;
40 import android.widget.Button;
41 import android.widget.TextView;
42 import com.google.zxing.Result;
43 import com.google.zxing.ResultPoint;
44 import com.google.zxing.client.result.ParsedResult;
45
46 import java.io.IOException;
47
48 /**
49  * The barcode reader activity itself. This is loosely based on the CameraPreview
50  * example included in the Android SDK.
51  */
52 public final class BarcodesCaptureActivity extends Activity implements SurfaceHolder.Callback {
53
54     private static final int SETTINGS_ID = Menu.FIRST;
55     private static final int HELP_ID = Menu.FIRST + 1;
56     private static final int ABOUT_ID = Menu.FIRST + 2;
57
58     public BarcodesCaptureActivityHandler mHandler;
59
60     private ViewfinderView mViewfinderView;
61     private MediaPlayer mMediaPlayer;
62     private String mLastResult;
63     private boolean mPlayBeep;
64     private boolean mScanIntent;
65     private String mDecodeMode;
66
67     @Override
68     public void onCreate(Bundle icicle) {
69         super.onCreate(icicle);
70
71         Window window = getWindow();
72         window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
73         setContentView(R.layout.capture);
74
75         CameraManager.init(getApplication());
76         mViewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
77         mHandler = null;
78
79         SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
80         SurfaceHolder surfaceHolder = surfaceView.getHolder();
81         surfaceHolder.addCallback(this);
82         surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
83     }
84
85     @Override
86     protected void onResume() {
87         super.onResume();
88         resetStatusView();
89
90         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
91         mPlayBeep = prefs.getBoolean(BarcodesPreferenceActivity.KEY_PLAY_BEEP, true);
92         initBeepSound();
93
94         Intent intent = getIntent();
95         if (intent != null && intent.getAction().equals(Intents.Scan.ACTION)) {
96             mScanIntent = true;
97             mDecodeMode = intent.getStringExtra(Intents.Scan.MODE);
98         } else {
99             mScanIntent = false;
100             mDecodeMode = null;
101         }
102     }
103
104     @Override
105     protected void onPause() {
106         super.onPause();
107         if (mHandler != null) {
108             mHandler.quitSynchronously();
109             mHandler = null;
110         }
111         CameraManager.get().closeDriver();
112     }
113
114     @Override
115     public boolean onKeyDown(int keyCode, KeyEvent event) {
116         if (keyCode == KeyEvent.KEYCODE_BACK) {
117             if (mScanIntent) {
118                 setResult(RESULT_CANCELED);
119                 finish();
120                 return true;
121             }
122         } else if (keyCode == KeyEvent.KEYCODE_FOCUS || keyCode == KeyEvent.KEYCODE_CAMERA) {
123             // Handle these events so they don't launch the Camera app
124             return true;
125         }
126         return super.onKeyDown(keyCode, event);
127     }
128
129     @Override
130     public boolean onCreateOptionsMenu(Menu menu) {
131         super.onCreateOptionsMenu(menu);
132         menu.add(0, SETTINGS_ID, 0, R.string.menu_settings)
133                 .setIcon(android.R.drawable.ic_menu_preferences);
134         menu.add(0, HELP_ID, 0, R.string.menu_help)
135                 .setIcon(android.R.drawable.ic_menu_help);
136         menu.add(0, ABOUT_ID, 0, R.string.menu_about)
137                 .setIcon(android.R.drawable.ic_menu_info_details);
138         return true;
139     }
140
141     @Override
142     public boolean onOptionsItemSelected(MenuItem item) {
143         switch (item.getItemId()) {
144             case SETTINGS_ID: {
145                 Intent intent = new Intent(Intent.ACTION_VIEW);
146                 intent.setClassName(this, BarcodesPreferenceActivity.class.getName());
147                 startActivity(intent);
148                 break;
149             }
150             case HELP_ID: {
151                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
152                 builder.setTitle(R.string.title_help);
153                 builder.setMessage(R.string.msg_help);
154                 builder.setPositiveButton(R.string.button_ok, null);
155                 builder.show();
156                 break;
157             }
158             case ABOUT_ID: {
159                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
160                 builder.setTitle(R.string.title_about);
161                 builder.setMessage(getString(R.string.msg_about) + "\n\n" + getString(R.string.zxing_url));
162                 builder.setIcon(R.drawable.zxing_icon);
163                 builder.setPositiveButton(R.string.button_open_browser, mAboutListener);
164                 builder.setNegativeButton(R.string.button_cancel, null);
165                 builder.show();
166                 break;
167             }
168         }
169         return super.onOptionsItemSelected(item);
170     }
171
172     private final DialogInterface.OnClickListener mAboutListener = new DialogInterface.OnClickListener() {
173         public void onClick(android.content.DialogInterface dialogInterface, int i) {
174             Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.zxing_url)));
175             startActivity(intent);
176         }
177     };
178
179     public void surfaceCreated(SurfaceHolder holder) {
180         CameraManager.get().openDriver(holder);
181         if (mHandler == null) {
182             mHandler = new BarcodesCaptureActivityHandler(this, mDecodeMode);
183         }
184     }
185
186     public void surfaceDestroyed(SurfaceHolder holder) {
187
188     }
189
190     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
191
192     }
193
194     /**
195      * A valid barcode has been found, so give an indication of success and show the results.
196      *
197      * @param rawResult The contents of the barcode.
198      * @param duration  How long the decoding took in milliseconds.
199      */
200     public void handleDecode(Result rawResult, int duration) {
201         if (!rawResult.toString().equals(mLastResult)) {
202             mLastResult = rawResult.toString();
203             playBeepSound();
204
205             ResultPoint[] points = rawResult.getResultPoints();
206             if (points != null && points.length > 0) {
207                 mViewfinderView.drawResultPoints(points);
208             }
209
210             TextView textView = (TextView) findViewById(R.id.status_text_view);
211             ParsedResult result = ResultHandler.parseResult(rawResult);
212             String displayResult = result.getDisplayResult();
213             displayResult = displayResult.replace("\r", "");
214             textView.setText(displayResult);
215
216             if (!mScanIntent) {
217                 Button actionButton = (Button) findViewById(R.id.status_action_button);
218                 int buttonText = ResultHandler.getActionButtonText(result.getType());
219                 if (buttonText != 0) {
220                     actionButton.setVisibility(View.VISIBLE);
221                     actionButton.setText(buttonText);
222                     ResultHandler resultHandler = new ResultHandler(this, result);
223                     actionButton.setOnClickListener(resultHandler);
224                     actionButton.requestFocus();
225                 } else {
226                     actionButton.setVisibility(View.GONE);
227                 }
228             }
229
230             View statusView = findViewById(R.id.status_view);
231             statusView.setBackgroundColor(getResources().getColor(R.color.result_points));
232
233             // Show the green finder patterns briefly, then either return the result or go back to
234             // continuous scanning.
235             if (mScanIntent) {
236                 Intent intent = new Intent(Intents.Scan.ACTION);
237                 intent.putExtra(Intents.Scan.RESULT,  rawResult.toString());
238                 intent.putExtra(Intents.Scan.RESULT_FORMAT, rawResult.getBarcodeFormat().toString());
239                 Message message = Message.obtain(mHandler, R.id.return_scan_result);
240                 message.obj = intent;
241                 mHandler.sendMessageDelayed(message, 1000);
242             } else {
243                 Message message = Message.obtain(mHandler, R.id.restart_preview);
244                 mHandler.sendMessageDelayed(message, 2000);
245             }
246         } else if (mHandler != null) {
247             Message message = Message.obtain(mHandler, R.id.restart_preview);
248             message.sendToTarget();
249         }
250     }
251
252     /**
253      * Creates the beep MediaPlayer in advance so that the sound can be triggered with the least
254      * latency possible.
255      */
256     private void initBeepSound() {
257         if (mPlayBeep && mMediaPlayer == null) {
258             mMediaPlayer = new MediaPlayer();
259             mMediaPlayer.setAudioStreamType(AudioManager.STREAM_SYSTEM);
260             mMediaPlayer.setOnCompletionListener(mBeepListener);
261
262             AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
263             try {
264                 mMediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(),
265                         file.getLength());
266                 file.close();
267                 mMediaPlayer.setVolume(0.15f, 0.15f);
268                 mMediaPlayer.prepare();
269             } catch (IOException e) {
270                 mMediaPlayer = null;
271             }
272         }
273     }
274
275     private void playBeepSound() {
276         if (mPlayBeep && mMediaPlayer != null) {
277             mMediaPlayer.start();
278         }
279     }
280
281     /**
282      * When the beep has finished playing, rewind to queue up another one.
283      */
284     private final OnCompletionListener mBeepListener = new OnCompletionListener() {
285         public void onCompletion(MediaPlayer mediaPlayer) {
286             mediaPlayer.seekTo(0);
287         }
288     };
289
290     private void resetStatusView() {
291         resetStatusViewColor();
292         TextView textView = (TextView) findViewById(R.id.status_text_view);
293         textView.setText(R.string.msg_default_status);
294         Button actionButton = (Button) findViewById(R.id.status_action_button);
295         actionButton.setVisibility(View.GONE);
296         mLastResult = "";
297     }
298
299     public void resetStatusViewColor() {
300         View statusView = findViewById(R.id.status_view);
301         statusView.setBackgroundColor(getResources().getColor(R.color.status_view));
302     }
303
304     public void drawViewfinder() {
305         mViewfinderView.drawViewfinder();
306     }
307
308 }