ScannerView.java

  1/*
  2 * Copyright 2012-2015 the original author or authors.
  3 *
  4 * This program is free software: you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License as published by
  6 * the Free Software Foundation, either version 3 of the License, or
  7 * (at your option) any later version.
  8 *
  9 * This program is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 * GNU General Public License for more details.
 13 *
 14 * You should have received a copy of the GNU General Public License
 15 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 16 */
 17
 18package eu.siacs.conversations.ui.widget;
 19
 20import android.content.Context;
 21import android.content.res.Resources;
 22import android.graphics.Canvas;
 23import android.graphics.Matrix;
 24import android.graphics.Matrix.ScaleToFit;
 25import android.graphics.Paint;
 26import android.graphics.Paint.Style;
 27import android.graphics.Rect;
 28import android.graphics.RectF;
 29import android.util.AttributeSet;
 30import android.view.View;
 31
 32import com.google.zxing.ResultPoint;
 33
 34import java.util.HashMap;
 35import java.util.Iterator;
 36import java.util.Map;
 37
 38import eu.siacs.conversations.R;
 39
 40/**
 41 * @author Andreas Schildbach
 42 */
 43public class ScannerView extends View {
 44    private static final long LASER_ANIMATION_DELAY_MS = 100l;
 45    private static final int DOT_OPACITY = 0xa0;
 46    private static final int DOT_TTL_MS = 500;
 47
 48    private final Paint maskPaint;
 49    private final Paint laserPaint;
 50    private final Paint dotPaint;
 51    private boolean isResult;
 52    private final int maskColor, maskResultColor;
 53    private final int laserColor;
 54    private final int dotColor, dotResultColor;
 55    private final Map<float[], Long> dots = new HashMap<float[], Long>(16);
 56    private Rect frame;
 57    private final Matrix matrix = new Matrix();
 58
 59    public ScannerView(final Context context, final AttributeSet attrs) {
 60        super(context, attrs);
 61
 62        final Resources res = getResources();
 63        maskColor = res.getColor(R.color.black54);
 64        maskResultColor = res.getColor(R.color.black87);
 65        laserColor = res.getColor(R.color.red500);
 66        dotColor = res.getColor(R.color.orange500);
 67        dotResultColor = res.getColor(R.color.scan_result_dots);
 68
 69        maskPaint = new Paint();
 70        maskPaint.setStyle(Style.FILL);
 71
 72        laserPaint = new Paint();
 73        laserPaint.setStrokeWidth(res.getDimensionPixelSize(R.dimen.scan_laser_width));
 74        laserPaint.setStyle(Style.STROKE);
 75
 76        dotPaint = new Paint();
 77        dotPaint.setAlpha(DOT_OPACITY);
 78        dotPaint.setStyle(Style.STROKE);
 79        dotPaint.setStrokeWidth(res.getDimension(R.dimen.scan_dot_size));
 80        dotPaint.setAntiAlias(true);
 81    }
 82
 83    public void setFraming(final Rect frame, final RectF framePreview, final int displayRotation,
 84            final int cameraRotation, final boolean cameraFlip) {
 85        this.frame = frame;
 86        matrix.setRectToRect(framePreview, new RectF(frame), ScaleToFit.FILL);
 87        matrix.postRotate(-displayRotation, frame.exactCenterX(), frame.exactCenterY());
 88        matrix.postScale(cameraFlip ? -1 : 1, 1, frame.exactCenterX(), frame.exactCenterY());
 89        matrix.postRotate(cameraRotation, frame.exactCenterX(), frame.exactCenterY());
 90
 91        invalidate();
 92    }
 93
 94    public void setIsResult(final boolean isResult) {
 95        this.isResult = isResult;
 96
 97        invalidate();
 98    }
 99
100    public void addDot(final ResultPoint dot) {
101        dots.put(new float[] { dot.getX(), dot.getY() }, System.currentTimeMillis());
102
103        invalidate();
104    }
105
106    @Override
107    public void onDraw(final Canvas canvas) {
108        if (frame == null)
109            return;
110
111        final long now = System.currentTimeMillis();
112
113        final int width = canvas.getWidth();
114        final int height = canvas.getHeight();
115
116        final float[] point = new float[2];
117
118        // draw mask darkened
119        maskPaint.setColor(isResult ? maskResultColor : maskColor);
120        canvas.drawRect(0, 0, width, frame.top, maskPaint);
121        canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, maskPaint);
122        canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, maskPaint);
123        canvas.drawRect(0, frame.bottom + 1, width, height, maskPaint);
124
125        if (isResult) {
126            laserPaint.setColor(dotResultColor);
127            laserPaint.setAlpha(160);
128
129            dotPaint.setColor(dotResultColor);
130        } else {
131            laserPaint.setColor(laserColor);
132            final boolean laserPhase = (now / 600) % 2 == 0;
133            laserPaint.setAlpha(laserPhase ? 160 : 255);
134
135            dotPaint.setColor(dotColor);
136
137            // schedule redraw
138            postInvalidateDelayed(LASER_ANIMATION_DELAY_MS);
139        }
140
141        canvas.drawRect(frame, laserPaint);
142
143        // draw points
144        for (final Iterator<Map.Entry<float[], Long>> i = dots.entrySet().iterator(); i.hasNext();) {
145            final Map.Entry<float[], Long> entry = i.next();
146            final long age = now - entry.getValue();
147            if (age < DOT_TTL_MS) {
148                dotPaint.setAlpha((int) ((DOT_TTL_MS - age) * 256 / DOT_TTL_MS));
149
150                matrix.mapPoints(point, entry.getKey());
151                canvas.drawPoint(point[0], point[1], dotPaint);
152            } else {
153                i.remove();
154            }
155        }
156    }
157}