blob: b5453ca46c1fd1e09964d357792749299dab8fa8 [file] [log] [blame]
/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.client.android;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.client.result.ParsedReaderResult;
import com.google.zxing.client.result.ParsedReaderResultType;
/**
* The barcode reader activity itself. This is loosely based on the CameraPreview
* example included in the Android SDK.
*
* @author dswitkin@google.com (Daniel Switkin)
* @author Android Team (for CameraPreview example)
*/
public final class BarcodeReaderCaptureActivity extends Activity {
private CameraManager cameraManager;
private CameraSurfaceView surfaceView;
private CameraThread cameraThread;
private static final int ABOUT_ID = Menu.FIRST;
private static final int HELP_ID = Menu.FIRST + 1;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
requestWindowFeature(Window.FEATURE_NO_TITLE);
// Make sure to create a TRANSLUCENT window. This is required for SurfaceView to work.
// Eventually this'll be done by the system automatically.
getWindow().setAttributes(new LayoutParams(LayoutParams.APPLICATION_TYPE,
LayoutParams.NO_STATUS_BAR_FLAG));
getWindow().setFormat(PixelFormat.TRANSLUCENT);
cameraManager = new CameraManager(getApplication());
surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
setContentView(surfaceView);
cameraThread = new CameraThread(this, surfaceView, cameraManager, messageHandler);
cameraThread.start();
// TODO re-enable this when issues with Matrix.setPolyToPoly() are resolved
//GridSampler.setGridSampler(new AndroidGraphicsGridSampler());
}
@Override
protected boolean isFullscreenOpaque() {
// Our main window is set to translucent, but we know that we will
// fill it with opaque data. Tell the system that so it can perform
// some important optimizations.
return true;
}
@Override
protected void onResume() {
super.onResume();
cameraManager.openDriver();
if (cameraThread == null) {
cameraThread = new CameraThread(this, surfaceView, cameraManager, messageHandler);
cameraThread.start();
}
}
@Override
protected void onPause() {
super.onPause();
if (cameraThread != null) {
cameraThread.quitSynchronously();
cameraThread = null;
}
cameraManager.closeDriver();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_A) {
cameraThread.setDecodeAllMode();
} else if (keyCode == KeyEvent.KEYCODE_C) {
Message save = Message.obtain(cameraThread.handler, R.id.save);
save.sendToTarget();
} else if (keyCode == KeyEvent.KEYCODE_P) {
cameraManager.setUsePreviewForDecode(true);
} else if (keyCode == KeyEvent.KEYCODE_Q) {
cameraThread.setDecodeQRMode();
} else if (keyCode == KeyEvent.KEYCODE_S) {
cameraManager.setUsePreviewForDecode(false);
} else if (keyCode == KeyEvent.KEYCODE_T) {
cameraThread.toggleTracing();
} else if (keyCode == KeyEvent.KEYCODE_U) {
cameraThread.setDecode1DMode();
} else {
return super.onKeyDown(keyCode, event);
}
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, ABOUT_ID, R.string.menu_about);
menu.add(0, HELP_ID, R.string.menu_help);
return true;
}
@Override
public boolean onOptionsItemSelected(Menu.Item item) {
Context context = getApplication();
switch (item.getId()) {
case ABOUT_ID:
showAlert(context.getString(R.string.title_about),
context.getString(R.string.msg_about),
context.getString(R.string.button_ok), null, true, null);
break;
case HELP_ID:
showAlert(context.getString(R.string.title_help),
context.getString(R.string.msg_help),
context.getString(R.string.button_ok), null, true, null);
break;
}
return super.onOptionsItemSelected(item);
}
private final Handler messageHandler = new Handler() {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case R.id.decode_succeeded:
int duration = message.arg1;
handleDecode((Result) message.obj, duration);
break;
}
}
};
public void restartPreview() {
Message restart = Message.obtain(cameraThread.handler, R.id.restart_preview);
restart.sendToTarget();
}
// TODO(dswitkin): These deprecated showAlert calls need to be updated.
private void handleDecode(Result rawResult, int duration) {
ResultPoint[] points = rawResult.getResultPoints();
if (points != null && points.length > 0) {
surfaceView.drawResultPoints(points);
}
Context context = getApplication();
ParsedReaderResult readerResult = parseReaderResult(rawResult);
ResultHandler handler = new ResultHandler(this, readerResult);
if (handler.getIntent() != null) {
// Can be handled by some external app; ask if the user wants to
// proceed first though
Message yesMessage = handler.obtainMessage(R.string.button_yes);
Message noMessage = handler.obtainMessage(R.string.button_no);
String title = context.getString(getDialogTitleID(readerResult.getType())) +
" (" + duration + " ms)";
showAlert(title, readerResult.getDisplayResult(), context.getString(R.string.button_yes),
yesMessage, context.getString(R.string.button_no), noMessage, true, noMessage);
} else {
// Just show information to user
Message okMessage = handler.obtainMessage(R.string.button_ok);
String title = context.getString(R.string.title_barcode_detected) +
" (" + duration + " ms)";
showAlert(title, readerResult.getDisplayResult(), context.getString(R.string.button_ok),
okMessage, null, null, true, okMessage);
}
}
private static ParsedReaderResult parseReaderResult(Result rawResult) {
ParsedReaderResult readerResult = ParsedReaderResult.parseReaderResult(rawResult);
if (readerResult.getType().equals(ParsedReaderResultType.TEXT)) {
String rawText = rawResult.getText();
AndroidIntentParsedResult androidResult = AndroidIntentParsedResult.parse(rawText);
if (androidResult != null) {
Intent intent = androidResult.getIntent();
if (!Intent.VIEW_ACTION.equals(intent.getAction())) {
// For now, don't take anything that just parses as a View action. A lot
// of things are accepted as a View action by default.
readerResult = androidResult;
}
}
}
return readerResult;
}
private static int getDialogTitleID(ParsedReaderResultType type) {
if (type.equals(ParsedReaderResultType.ADDRESSBOOK)) {
return R.string.title_add_contact;
} else if (type.equals(ParsedReaderResultType.URI) ||
type.equals(ParsedReaderResultType.BOOKMARK) ||
type.equals(ParsedReaderResultType.URLTO)) {
return R.string.title_open_url;
} else if (type.equals(ParsedReaderResultType.EMAIL) ||
type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
return R.string.title_compose_email;
} else if (type.equals(ParsedReaderResultType.UPC)) {
return R.string.title_lookup_barcode;
} else if (type.equals(ParsedReaderResultType.TEL)) {
return R.string.title_dial;
} else if (type.equals(ParsedReaderResultType.GEO)) {
return R.string.title_view_maps;
} else {
return R.string.title_barcode_detected;
}
}
}