content: /*
   * Copyright (C) 2008 ZXing authors
   *
   * 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.view;
  
  import android.content.Context;
  import android.content.res.TypedArray;
  import android.graphics.Bitmap;
  import android.graphics.Canvas;
  import android.graphics.ComposeShader;
  import android.graphics.LinearGradient;
  import android.graphics.Paint;
  import android.graphics.PorterDuff;
  import android.graphics.RadialGradient;
  import android.graphics.Rect;
  import android.graphics.RectF;
  import android.graphics.Shader;
  import android.graphics.SweepGradient;
  import android.util.AttributeSet;
  import android.view.View;
  
  import com.google.zxing.R;
  import com.google.zxing.ResultPoint;
  import com.google.zxing.camera.CameraManager;
  
  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 = 10L;
      private static final int OPAQUE = 0xFF;
      private static final int CORNER_RECT_WIDTH = 10;  //扫描区边角的宽
      private static final int CORNER_RECT_HEIGHT = 50; //扫描区边角的高
      private static final int SCANNER_LINE_MOVE_DISTANCE = 5;  //扫描线移动距离
      private static final int SCANNER_LINE_HEIGHT = 10;  //扫描线宽度
  
      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 cornerColor;
      //扫描点的颜色
      private final int resultPointColor;
      private int scannerAlpha;
      //扫描区域提示文本
      private final String labelText;
      //扫描区域提示文本颜色
      private final int labelTextColor;
      private final float labelTextSize;
      private final float labelTextMarginTop;
  
      public static int scannerStart = 0;
      public static int scannerEnd = 0;
  
      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);
  
          //初始化自定义属性信息
          TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ViewfinderView);
          laserColor = array.getColor(R.styleable.ViewfinderView_laser_color, 0x00FF00);
          cornerColor = array.getColor(R.styleable.ViewfinderView_corner_color, 0x00FF00);
          frameColor = array.getColor(R.styleable.ViewfinderView_frame_color, 0xFFFFFF);
          resultPointColor = array.getColor(R.styleable.ViewfinderView_result_point_color, 0xC0FFFF00);
          maskColor = array.getColor(R.styleable.ViewfinderView_mask_color, 0x60000000);
          resultColor = array.getColor(R.styleable.ViewfinderView_result_color, 0xB0000000);
          labelTextColor = array.getColor(R.styleable.ViewfinderView_label_text_color, 0x90FFFFFF);
          labelText = array.getString(R.styleable.ViewfinderView_label_text);
          labelTextSize = array.getDimension(R.styleable.ViewfinderView_label_text_size, 36f);
          labelTextMarginTop = array.getDimension(R.styleable.ViewfinderView_label_text_margin_top, 0);
  
          // Initialize these once for performance rather than calling them every time in onDraw().
          paint = new Paint();
          paint.setAntiAlias(true);
          scannerAlpha = 0;
          possibleResultPoints = new HashSet<ResultPoint>(5);
  
  
      }
  
      @Override
      public void onDraw(Canvas canvas) {
          Rect frame = CameraManager.get().getFramingRect();
          if (frame == null) {
              return;
          }
          if (scannerStart == 0 || scannerEnd == 0) {
              scannerStart = frame.top;
              scannerEnd = frame.bottom;
          }
  
          int width = canvas.getWidth();
          int height = canvas.getHeight();
          // Draw the exterior (i.e. outside the framing rect) darkened
          drawExterior(canvas, frame, width, height);
  
  
          if (resultBitmap != null) {
              // Draw the opaque result bitmap over the scanning rectangle
              paint.setAlpha(OPAQUE);
              canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
          } else {
              // Draw a two pixel solid black border inside the framing rect
  //            drawFrame(canvas, frame);
              // 绘制边角
              drawCorner(canvas, frame);
              //绘制提示信息
              drawTextInfo(canvas, frame);
              // Draw a red "laser scanner" line through the middle to show decoding is active
              drawLaserScanner(canvas, frame);
  
  //            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, frame.left, frame.top, frame.right, frame.bottom);
          }
      }
  
      //绘制文本
      private void drawTextInfo(Canvas canvas, Rect frame) {
          paint.setColor(labelTextColor);
          paint.setTextSize(labelTextSize);
          paint.setTextAlign(Paint.Align.CENTER);
          canvas.drawText(labelText, frame.left + frame.width() / 2, frame.bottom + CORNER_RECT_HEIGHT * 1.5f + labelTextMarginTop, paint);
      }
  
  
      //绘制边角
      private void drawCorner(Canvas canvas, Rect frame) {
          paint.setColor(cornerColor);
          //左上
          canvas.drawRect(frame.left, frame.top, frame.left + CORNER_RECT_WIDTH, frame.top + CORNER_RECT_HEIGHT, paint);
          canvas.drawRect(frame.left, frame.top, frame.left + CORNER_RECT_HEIGHT, frame.top + CORNER_RECT_WIDTH, paint);
          //右上
          canvas.drawRect(frame.right - CORNER_RECT_WIDTH, frame.top, frame.right, frame.top + CORNER_RECT_HEIGHT, paint);
          canvas.drawRect(frame.right - CORNER_RECT_HEIGHT, frame.top, frame.right, frame.top + CORNER_RECT_WIDTH, paint);
          //左下
          canvas.drawRect(frame.left, frame.bottom - CORNER_RECT_WIDTH, frame.left + CORNER_RECT_HEIGHT, frame.bottom, paint);
          canvas.drawRect(frame.left, frame.bottom - CORNER_RECT_HEIGHT, frame.left + CORNER_RECT_WIDTH, frame.bottom, paint);
          //右下
          canvas.drawRect(frame.right - CORNER_RECT_WIDTH, frame.bottom - CORNER_RECT_HEIGHT, frame.right, frame.bottom, paint);
          canvas.drawRect(frame.right - CORNER_RECT_HEIGHT, frame.bottom - CORNER_RECT_WIDTH, frame.right, frame.bottom, paint);
      }
  
      //绘制扫描线
      private void drawLaserScanner(Canvas canvas, Rect frame) {
          paint.setColor(laserColor);
          //扫描线闪烁效果
  //    paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
  //    scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
  //    int middle = frame.height() / 2 + frame.top;
  //    canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
          //线性渐变
          LinearGradient linearGradient = new LinearGradient(
                  frame.left, scannerStart,
                  frame.left, scannerStart + SCANNER_LINE_HEIGHT,
                  shadeColor(laserColor),
                  laserColor,
                  Shader.TileMode.MIRROR);
  
          RadialGradient radialGradient = new RadialGradient(
                  (float) (frame.left + frame.width() / 2),
                  (float) (scannerStart + SCANNER_LINE_HEIGHT / 2),
                  360f,
                  laserColor,
                  shadeColor(laserColor),
                  Shader.TileMode.MIRROR);
  
          SweepGradient sweepGradient = new SweepGradient(
                  (float) (frame.left + frame.width() / 2),
                  (float) (scannerStart + SCANNER_LINE_HEIGHT),
                  shadeColor(laserColor),
                  laserColor);
  
          ComposeShader composeShader = new ComposeShader(radialGradient, linearGradient, PorterDuff.Mode.ADD);
  
          paint.setShader(radialGradient);
          if (scannerStart <= scannerEnd) {
              //矩形
  //      canvas.drawRect(frame.left, scannerStart, frame.right, scannerStart + SCANNER_LINE_HEIGHT, paint);
              //椭圆
              RectF rectF = new RectF(frame.left + 2 * SCANNER_LINE_HEIGHT, scannerStart, frame.right - 2 * SCANNER_LINE_HEIGHT, scannerStart + SCANNER_LINE_HEIGHT);
              canvas.drawOval(rectF, paint);
              scannerStart += SCANNER_LINE_MOVE_DISTANCE;
          } else {
              scannerStart = frame.top;
          }
          paint.setShader(null);
      }
  
      //处理颜色模糊
      public int shadeColor(int color) {
          String hax = Integer.toHexString(color);
          String result = "20" + hax.substring(2);
          return Integer.valueOf(result, 16);
      }
  
      // 绘制扫描区边框 Draw a two pixel solid black border inside the framing rect
      private void drawFrame(Canvas canvas, Rect frame) {
          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 the exterior (i.e. outside the framing rect) darkened
      private void drawExterior(Canvas canvas, Rect frame, int width, int height) {
          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);
      }
  
      public void drawViewfinder() {
          resultBitmap = null;
          invalidate();
      }
  
      /**
       * Draw a bitmap with the result points highlighted instead of the live scanning display.
       *
       * @param barcode An image of the decoded barcode.
       */
      public void drawResultBitmap(Bitmap barcode) {
          resultBitmap = barcode;
          invalidate();
      }
  
      public void addPossibleResultPoint(ResultPoint point) {
          possibleResultPoints.add(point);
      }
  
  }
  