Backing out this change for the Droid on suspicion that it's interfering with at...
[zxing.git] / android / src / com / google / zxing / client / android / ViewfinderView.java
index 47d82af..8696062 100755 (executable)
@@ -16,6 +16,9 @@
 
 package com.google.zxing.client.android;
 
+import com.google.zxing.ResultPoint;
+import com.google.zxing.client.android.camera.CameraManager;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -25,88 +28,113 @@ import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
 
+import java.util.Collection;
+import java.util.HashSet;
+
 /**
  * This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
  * transparency outside it, as well as the laser scanner animation and result points.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
  */
 public final class ViewfinderView extends View {
 
   private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
   private static final long ANIMATION_DELAY = 100L;
+  private static final int OPAQUE = 0xFF;
 
-  private final Paint mPaint;
-  private final Rect mBox;
-  private Bitmap mResultBitmap;
-  private final int mMaskColor;
-  private final int mResultColor;
-  private final int mFrameColor;
-  private final int mLaserColor;
-  private int mScannerAlpha;
+  private final Paint paint;
+  private Bitmap resultBitmap;
+  private final int maskColor;
+  private final int resultColor;
+  private final int frameColor;
+  private final int laserColor;
+  private final int resultPointColor;
+  private int scannerAlpha;
+  private Collection<ResultPoint> possibleResultPoints;
+  private Collection<ResultPoint> lastPossibleResultPoints;
 
   // This constructor is used when the class is built from an XML resource.
   public ViewfinderView(Context context, AttributeSet attrs) {
     super(context, attrs);
 
     // Initialize these once for performance rather than calling them every time in onDraw().
-    mPaint = new Paint();
-    mBox = new Rect();
+    paint = new Paint();
     Resources resources = getResources();
-    mMaskColor = resources.getColor(R.color.viewfinder_mask);
-    mResultColor = resources.getColor(R.color.result_view);
-    mFrameColor = resources.getColor(R.color.viewfinder_frame);
-    mLaserColor = resources.getColor(R.color.viewfinder_laser);
-    mScannerAlpha = 0;
+    maskColor = resources.getColor(R.color.viewfinder_mask);
+    resultColor = resources.getColor(R.color.result_view);
+    frameColor = resources.getColor(R.color.viewfinder_frame);
+    laserColor = resources.getColor(R.color.viewfinder_laser);
+    resultPointColor = resources.getColor(R.color.possible_result_points);
+    scannerAlpha = 0;
+    possibleResultPoints = new HashSet<ResultPoint>(5);
   }
 
   @Override
   public void onDraw(Canvas canvas) {
     Rect frame = CameraManager.get().getFramingRect();
+    if (frame == null) {
+      return;
+    }
     int width = canvas.getWidth();
     int height = canvas.getHeight();
 
     // Draw the exterior (i.e. outside the framing rect) darkened
-    mPaint.setColor(mResultBitmap != null ? mResultColor : mMaskColor);
-    mBox.set(0, 0, width, frame.top);
-    canvas.drawRect(mBox, mPaint);
-    mBox.set(0, frame.top, frame.left, frame.bottom + 1);
-    canvas.drawRect(mBox, mPaint);
-    mBox.set(frame.right + 1, frame.top, width, frame.bottom + 1);
-    canvas.drawRect(mBox, mPaint);
-    mBox.set(0, frame.bottom + 1, width, height);
-    canvas.drawRect(mBox, mPaint);
-
-    if (mResultBitmap != null) {
+    paint.setColor(resultBitmap != null ? resultColor : maskColor);
+    canvas.drawRect(0, 0, width, frame.top, paint);
+    canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
+    canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
+    canvas.drawRect(0, frame.bottom + 1, width, height, paint);
+
+    if (resultBitmap != null) {
       // Draw the opaque result bitmap over the scanning rectangle
-      mPaint.setAlpha(255);
-      canvas.drawBitmap(mResultBitmap, frame.left, frame.top, mPaint);
+      paint.setAlpha(OPAQUE);
+      canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
     } else {
+
       // Draw a two pixel solid black border inside the framing rect
-      mPaint.setColor(mFrameColor);
-      mBox.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
-      canvas.drawRect(mBox, mPaint);
-      mBox.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
-      canvas.drawRect(mBox, mPaint);
-      mBox.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
-      canvas.drawRect(mBox, mPaint);
-      mBox.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
-      canvas.drawRect(mBox, mPaint);
+      paint.setColor(frameColor);
+      canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
+      canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
+      canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
+      canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);
 
       // Draw a red "laser scanner" line through the middle to show decoding is active
-      mPaint.setColor(mLaserColor);
-      mPaint.setAlpha(SCANNER_ALPHA[mScannerAlpha]);
-      mScannerAlpha = (mScannerAlpha + 1) % SCANNER_ALPHA.length;
+      paint.setColor(laserColor);
+      paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
+      scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
       int middle = frame.height() / 2 + frame.top;
-      mBox.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
-      canvas.drawRect(mBox, mPaint);
+      canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
+
+      Collection<ResultPoint> currentPossible = possibleResultPoints;
+      Collection<ResultPoint> currentLast = lastPossibleResultPoints;
+      if (currentPossible.isEmpty()) {
+        lastPossibleResultPoints = null;
+      } else {
+        possibleResultPoints = new HashSet<ResultPoint>(5);
+        lastPossibleResultPoints = currentPossible;
+        paint.setAlpha(OPAQUE);
+        paint.setColor(resultPointColor);
+        for (ResultPoint point : currentPossible) {
+          canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint);
+        }
+      }
+      if (currentLast != null) {
+        paint.setAlpha(OPAQUE / 2);
+        paint.setColor(resultPointColor);
+        for (ResultPoint point : currentLast) {
+          canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint);
+        }
+      }
 
       // Request another update at the animation interval, but only repaint the laser line,
       // not the entire viewfinder mask.
-      postInvalidateDelayed(ANIMATION_DELAY, mBox.left, mBox.top, mBox.right, mBox.bottom);
+      postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);
     }
   }
 
   public void drawViewfinder() {
-    mResultBitmap = null;
+    resultBitmap = null;
     invalidate();
   }
 
@@ -116,8 +144,12 @@ public final class ViewfinderView extends View {
    * @param barcode An image of the decoded barcode.
    */
   public void drawResultBitmap(Bitmap barcode) {
-    mResultBitmap = barcode;
+    resultBitmap = barcode;
     invalidate();
   }
 
+  public void addPossibleResultPoint(ResultPoint point) {
+    possibleResultPoints.add(point);
+  }
+
 }