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.android.barcodes;
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.content.res.Configuration;
26 import android.media.MediaPlayer;
27 import android.media.AudioManager;
28 import android.media.MediaPlayer.OnCompletionListener;
29 import android.net.Uri;
30 import android.os.Bundle;
31 import android.os.Message;
32 import android.preference.PreferenceManager;
33 import android.view.KeyEvent;
34 import android.view.Menu;
35 import android.view.MenuItem;
36 import android.view.SurfaceHolder;
37 import android.view.SurfaceView;
38 import android.view.View;
39 import android.view.Window;
40 import android.view.WindowManager;
41 import android.widget.Button;
42 import android.widget.TextView;
43 import com.google.zxing.Result;
44 import com.google.zxing.ResultPoint;
45 import com.google.zxing.client.result.ParsedResult;
47 import java.io.IOException;
50 * The barcode reader activity itself. This is loosely based on the CameraPreview
51 * example included in the Android SDK.
53 public final class BarcodesCaptureActivity extends Activity implements SurfaceHolder.Callback {
55 private static final int SETTINGS_ID = Menu.FIRST;
56 private static final int HELP_ID = Menu.FIRST + 1;
57 private static final int ABOUT_ID = Menu.FIRST + 2;
59 public BarcodesCaptureActivityHandler mHandler;
61 private ViewfinderView mViewfinderView;
62 private MediaPlayer mMediaPlayer;
63 private String mLastResult;
64 private boolean mPlayBeep;
65 private boolean mScanIntent;
66 private String mDecodeMode;
69 public void onCreate(Bundle icicle) {
70 super.onCreate(icicle);
72 Window window = getWindow();
73 window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
74 setContentView(R.layout.capture);
76 CameraManager.init(getApplication());
77 mViewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
80 SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
81 SurfaceHolder surfaceHolder = surfaceView.getHolder();
82 surfaceHolder.addCallback(this);
83 surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
87 protected void onResume() {
91 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
92 mPlayBeep = prefs.getBoolean(BarcodesPreferenceActivity.KEY_PLAY_BEEP, true);
95 Intent intent = getIntent();
96 if (intent != null && intent.getAction().equals(Intents.Scan.ACTION)) {
98 mDecodeMode = intent.getStringExtra(Intents.Scan.MODE);
106 protected void onPause() {
108 if (mHandler != null) {
109 mHandler.quitSynchronously();
112 CameraManager.get().closeDriver();
116 public boolean onKeyDown(int keyCode, KeyEvent event) {
117 if (keyCode == KeyEvent.KEYCODE_BACK) {
119 setResult(RESULT_CANCELED);
123 } else if (keyCode == KeyEvent.KEYCODE_FOCUS || keyCode == KeyEvent.KEYCODE_CAMERA) {
124 // Handle these events so they don't launch the Camera app
127 return super.onKeyDown(keyCode, event);
131 public boolean onCreateOptionsMenu(Menu menu) {
132 super.onCreateOptionsMenu(menu);
133 menu.add(0, SETTINGS_ID, 0, R.string.menu_settings)
134 .setIcon(android.R.drawable.ic_menu_preferences);
135 menu.add(0, HELP_ID, 0, R.string.menu_help)
136 .setIcon(android.R.drawable.ic_menu_help);
137 menu.add(0, ABOUT_ID, 0, R.string.menu_about)
138 .setIcon(android.R.drawable.ic_menu_info_details);
143 public boolean onOptionsItemSelected(MenuItem item) {
144 switch (item.getItemId()) {
146 Intent intent = new Intent(Intent.ACTION_VIEW);
147 intent.setClassName(this, BarcodesPreferenceActivity.class.getName());
148 startActivity(intent);
152 AlertDialog.Builder builder = new AlertDialog.Builder(this);
153 builder.setTitle(R.string.title_help);
154 builder.setMessage(R.string.msg_help);
155 builder.setPositiveButton(R.string.button_ok, null);
160 AlertDialog.Builder builder = new AlertDialog.Builder(this);
161 builder.setTitle(R.string.title_about);
162 builder.setMessage(getString(R.string.msg_about) + "\n\n" + getString(R.string.zxing_url));
163 builder.setIcon(R.drawable.zxing_icon);
164 builder.setPositiveButton(R.string.button_open_browser, mAboutListener);
165 builder.setNegativeButton(R.string.button_cancel, null);
170 return super.onOptionsItemSelected(item);
174 public void onConfigurationChanged(Configuration config) {
175 // Do nothing, this is to prevent the activity from being restarted when the keyboard opens.
176 super.onConfigurationChanged(config);
179 private final DialogInterface.OnClickListener mAboutListener = new DialogInterface.OnClickListener() {
180 public void onClick(android.content.DialogInterface dialogInterface, int i) {
181 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.zxing_url)));
182 startActivity(intent);
186 public void surfaceCreated(SurfaceHolder holder) {
187 CameraManager.get().openDriver(holder);
188 if (mHandler == null) {
189 mHandler = new BarcodesCaptureActivityHandler(this, mDecodeMode);
193 public void surfaceDestroyed(SurfaceHolder holder) {
197 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
202 * A valid barcode has been found, so give an indication of success and show the results.
204 * @param rawResult The contents of the barcode.
205 * @param duration How long the decoding took in milliseconds.
207 public void handleDecode(Result rawResult, int duration) {
208 if (!rawResult.toString().equals(mLastResult)) {
209 mLastResult = rawResult.toString();
212 ResultPoint[] points = rawResult.getResultPoints();
213 if (points != null && points.length > 0) {
214 mViewfinderView.drawResultPoints(points);
217 TextView textView = (TextView) findViewById(R.id.status_text_view);
218 ParsedResult result = ResultHandler.parseResult(rawResult);
219 String displayResult = result.getDisplayResult();
220 displayResult = displayResult.replace("\r", "");
221 textView.setText(displayResult);
224 Button actionButton = (Button) findViewById(R.id.status_action_button);
225 int buttonText = ResultHandler.getActionButtonText(result.getType());
226 if (buttonText != 0) {
227 actionButton.setVisibility(View.VISIBLE);
228 actionButton.setText(buttonText);
229 ResultHandler resultHandler = new ResultHandler(this, result);
230 actionButton.setOnClickListener(resultHandler);
231 actionButton.requestFocus();
233 actionButton.setVisibility(View.GONE);
237 View statusView = findViewById(R.id.status_view);
238 statusView.setBackgroundColor(getResources().getColor(R.color.result_points));
240 // Show the green finder patterns briefly, then either return the result or go back to
241 // continuous scanning.
243 Intent intent = new Intent(Intents.Scan.ACTION);
244 intent.putExtra(Intents.Scan.RESULT, rawResult.toString());
245 intent.putExtra(Intents.Scan.RESULT_FORMAT, rawResult.getBarcodeFormat().toString());
246 Message message = Message.obtain(mHandler, R.id.return_scan_result);
247 message.obj = intent;
248 mHandler.sendMessageDelayed(message, 1000);
250 Message message = Message.obtain(mHandler, R.id.restart_preview);
251 mHandler.sendMessageDelayed(message, 2000);
253 } else if (mHandler != null) {
254 Message message = Message.obtain(mHandler, R.id.restart_preview);
255 message.sendToTarget();
260 * Creates the beep MediaPlayer in advance so that the sound can be triggered with the least
263 private void initBeepSound() {
264 if (mPlayBeep && mMediaPlayer == null) {
265 mMediaPlayer = new MediaPlayer();
266 mMediaPlayer.setAudioStreamType(AudioManager.STREAM_SYSTEM);
267 mMediaPlayer.setOnCompletionListener(mBeepListener);
269 AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
271 mMediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(),
274 mMediaPlayer.setVolume(0.15f, 0.15f);
275 mMediaPlayer.prepare();
276 } catch (IOException e) {
282 private void playBeepSound() {
283 if (mPlayBeep && mMediaPlayer != null) {
284 mMediaPlayer.start();
289 * When the beep has finished playing, rewind to queue up another one.
291 private final OnCompletionListener mBeepListener = new OnCompletionListener() {
292 public void onCompletion(MediaPlayer mediaPlayer) {
293 mediaPlayer.seekTo(0);
297 private void resetStatusView() {
298 resetStatusViewColor();
299 TextView textView = (TextView) findViewById(R.id.status_text_view);
300 textView.setText(R.string.msg_default_status);
301 Button actionButton = (Button) findViewById(R.id.status_action_button);
302 actionButton.setVisibility(View.GONE);
306 public void resetStatusViewColor() {
307 View statusView = findViewById(R.id.status_view);
308 statusView.setBackgroundColor(getResources().getColor(R.color.status_view));
311 public void drawViewfinder() {
312 mViewfinderView.drawViewfinder();