Merged revisions 321,327,330,332,334,342-343,352-353,355-358,361-363,365,372 via...
[zxing.git] / android / src / com / google / zxing / client / android / BarcodeReaderCaptureActivity.java
index 6f7e24f..85b9bfd 100644 (file)
@@ -18,14 +18,17 @@ package com.google.zxing.client.android;
 
 import android.app.Activity;
 import android.content.Context;
-import android.graphics.PixelFormat;
+import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.view.KeyEvent;
 import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
 import android.view.Window;
-import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+import android.widget.TextView;
 import com.google.zxing.Result;
 import com.google.zxing.ResultPoint;
 import com.google.zxing.client.result.ParsedReaderResult;
@@ -34,162 +37,210 @@ 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 WorkerThread workerThread;
-  
+  private CameraThread cameraThread;
+  private String lastResult;
+
   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);
+    setContentView(R.layout.main);
 
     cameraManager = new CameraManager(getApplication());
     surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
-    setContentView(surfaceView);
-    workerThread = new WorkerThread(surfaceView, cameraManager, messageHandler);
-    workerThread.requestPreviewLoop();
-    workerThread.start();
-  }
-  
-  @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;
+    surfaceView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
+        ViewGroup.LayoutParams.FILL_PARENT));
+
+    ViewGroup previewView = (ViewGroup) findViewById(R.id.preview_view);
+    previewView.addView(surfaceView);
+    cameraThread = null;
+
+    // TODO re-enable this when issues with Matrix.setPolyToPoly() are resolved
+    //GridSampler.setGridSampler(new AndroidGraphicsGridSampler());
   }
 
   @Override
   protected void onResume() {
     super.onResume();
+    resetStatusView();
     cameraManager.openDriver();
-    if (workerThread == null) {
-      workerThread = new WorkerThread(surfaceView, cameraManager, messageHandler);
-      workerThread.requestPreviewLoop();
-      workerThread.start();
+    if (cameraThread == null) {
+      cameraThread = new CameraThread(this, surfaceView, cameraManager, messageHandler);
+      cameraThread.start();
     }
   }
 
   @Override
   protected void onPause() {
     super.onPause();
-    if (workerThread != null) {
-      workerThread.requestExitAndWait();
-      workerThread = null;
+    if (cameraThread != null) {
+      cameraThread.quitSynchronously();
+      cameraThread = null;
     }
     cameraManager.closeDriver();
   }
 
   @Override
   public boolean onKeyDown(int keyCode, KeyEvent event) {
-    if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
-      workerThread.requestStillAndDecode();
-      return true;
+    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);
-      return true;
+    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:
-        Context context = getApplication();
-        showAlert(context.getString(R.string.title_about),
-            context.getString(R.string.msg_about),
-            context.getString(R.string.button_ok), null, true, null);
+        showAlert(context.getString(R.string.title_about), 0,
+          context.getString(R.string.msg_about),
+          context.getString(R.string.button_ok),
+          true);
         break;
-      }
-      return super.onOptionsItemSelected(item);
+      case HELP_ID:
+        showAlert(context.getString(R.string.title_help), 0,
+            context.getString(R.string.msg_help),
+            context.getString(R.string.button_ok), true);
+        break;
+    }
+    return super.onOptionsItemSelected(item);
   }
-  
-  Handler messageHandler = new Handler() {
+
+  private final Handler messageHandler = new Handler() {
     @Override
     public void handleMessage(Message message) {
       switch (message.what) {
-      case R.id.decoding_succeeded_message:
-        handleDecode((Result)message.obj);
-        break;
-      case R.id.decoding_failed_message:
-        Context context = getApplication();
-        showAlert(context.getString(R.string.title_no_barcode_detected),
-            context.getString(R.string.msg_no_barcode_detected),
-            context.getString(R.string.button_ok), null, true, null);
-        break;
+        case R.id.decode_succeeded:
+          int duration = message.arg1;
+          handleDecode((Result) message.obj, duration);
+          break;
+        case R.id.restart_preview:
+          restartPreview();
+          break;
       }
     }
   };
-  
+
   public void restartPreview() {
-    workerThread.requestPreviewLoop();
+    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) {
-    ResultPoint[] points = rawResult.getResultPoints();
-    if (points != null && points.length > 0) {
-      surfaceView.drawResultPoints(points);
-    }
 
-    Context context = getApplication();
-    ParsedReaderResult readerResult = ParsedReaderResult.parseReaderResult(rawResult.getText());
-    Handler handler = new ResultHandler(this, readerResult);
-    if (canBeHandled(readerResult.getType())) {
-      // 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);
-      showAlert(context.getString(getDialogTitleID(readerResult.getType())),
-          readerResult.getDisplayResult(), context.getString(R.string.button_yes),
-          yesMessage, context.getString(R.string.button_no), noMessage, true, noMessage);
+  private void handleDecode(Result rawResult, int duration) {
+    if (!rawResult.toString().equals(lastResult)) {
+      lastResult = rawResult.toString();
+
+      ResultPoint[] points = rawResult.getResultPoints();
+      if (points != null && points.length > 0) {
+        surfaceView.drawResultPoints(points);
+      }
+
+      TextView textView = (TextView) findViewById(R.id.status_text_view);
+      ParsedReaderResult readerResult = parseReaderResult(rawResult);
+      textView.setText(readerResult.getDisplayResult() + " (" + duration + " ms)");
+
+      Button actionButton = (Button) findViewById(R.id.status_action_button);
+      int buttonText = getActionButtonText(readerResult.getType());
+      if (buttonText != 0) {
+        actionButton.setVisibility(View.VISIBLE);
+        actionButton.setText(buttonText);
+        ResultHandler handler = new ResultHandler(this, readerResult);
+        actionButton.setOnClickListener(handler);
+        actionButton.requestFocus();
+      } else {
+        actionButton.setVisibility(View.GONE);
+      }
+
+      // Show the green finder patterns for one second, then restart the preview
+      Message message = Message.obtain(messageHandler, R.id.restart_preview);
+      messageHandler.sendMessageDelayed(message, 1000);
     } else {
-      // Just show information to user
-      Message okMessage = handler.obtainMessage(R.string.button_ok);
-      showAlert(context.getString(R.string.title_barcode_detected),
-          readerResult.getDisplayResult(), context.getString(R.string.button_ok), okMessage, null,
-          null, true, okMessage);
+      restartPreview();
     }
   }
 
-  private static boolean canBeHandled(ParsedReaderResultType type) {
-    return type != ParsedReaderResultType.TEXT;
+  private void resetStatusView() {
+    TextView textView = (TextView) findViewById(R.id.status_text_view);
+    textView.setText(R.string.msg_default_status);
+    Button actionButton = (Button) findViewById(R.id.status_action_button);
+    actionButton.setVisibility(View.GONE);
+    lastResult = "";
+  }
+
+  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 == ParsedReaderResultType.ADDRESSBOOK) {
-      return R.string.title_add_contact;
-    } else if (type == ParsedReaderResultType.BOOKMARK) {
-      return R.string.title_open_url;
-    } else if (type == ParsedReaderResultType.EMAIL || type == ParsedReaderResultType.EMAIL_ADDRESS) {
-      return R.string.title_compose_email;
-    } else if (type == ParsedReaderResultType.UPC) {
-      return R.string.title_lookup_barcode;
-    } else if (type == ParsedReaderResultType.URI) {
-      return R.string.title_open_url;
+  private static int getActionButtonText(ParsedReaderResultType type) {
+    int buttonText;
+    if (type.equals(ParsedReaderResultType.ADDRESSBOOK)) {
+      buttonText = R.string.button_add_contact;
+    } else if (type.equals(ParsedReaderResultType.URI) ||
+               type.equals(ParsedReaderResultType.BOOKMARK) ||
+               type.equals(ParsedReaderResultType.URLTO)) {
+      buttonText = R.string.button_open_browser;
+    } else if (type.equals(ParsedReaderResultType.EMAIL) ||
+               type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
+      buttonText = R.string.button_email;
+    } else if (type.equals(ParsedReaderResultType.UPC)) {
+      buttonText = R.string.button_lookup_product;
+    } else if (type.equals(ParsedReaderResultType.TEL)) {
+      buttonText = R.string.button_dial;
+    } else if (type.equals(ParsedReaderResultType.GEO)) {
+      buttonText = R.string.button_show_map;
     } else {
-      return R.string.title_barcode_detected;
+      buttonText = 0;
     }
+    return buttonText;
   }
-  
+
 }
\ No newline at end of file