2 * Copyright (C) 2008 Google Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.google.zxing.client.android;
19 import com.google.zxing.ResultPoint;
21 import android.content.Context;
22 import android.graphics.Canvas;
23 import android.graphics.Color;
24 import android.graphics.Paint;
25 import android.graphics.Point;
26 import android.graphics.Rect;
27 import android.view.SurfaceHolder;
28 import android.view.SurfaceView;
31 * @author dswitkin@google.com (Daniel Switkin)
33 final class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
35 private static int[] SCANNER_ALPHA = { 0, 64, 128, 192, 255, 192, 128, 64 };
37 private CameraManager cameraManager;
38 private SurfaceHolder surfaceHolder;
39 private boolean hasSurface;
40 private int scannerAlpha;
42 CameraSurfaceView(Context context, CameraManager cameraManager) {
44 this.cameraManager = cameraManager;
46 // Install a SurfaceHolder.Callback so we get notified when the underlying surface is created
48 surfaceHolder = getHolder();
49 surfaceHolder.setCallback(this);
53 // FIXME(dswitkin): This resolution needs to be made dynamic to handle different devices and
55 surfaceHolder.setFixedSize(320, 240);
58 public boolean surfaceCreated(SurfaceHolder holder) {
61 // Tell the system that we filled the surface in this call. This is a lie to prevent the system
62 // from filling the surface for us automatically. THIS IS REQUIRED because otherwise we'll
63 // access the Surface object from 2 different threads which is not allowed.
67 public void surfaceDestroyed(SurfaceHolder holder) {
68 // FIXME(dswitkin): The docs say this surface will be destroyed when this method returns. In
69 // practice this has not been a problem so far. I need to investigate.
73 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
74 // Surface size or format has changed. This won't happen because of the setFixedSize() call.
78 * This method is only called from the WorkerThread. It's job is to grab the next preview frame
79 * from the camera, draw the framing rectangle, and blit everything to the screen.
81 public void capturePreviewAndDraw() {
83 Canvas canvas = surfaceHolder.lockCanvas();
84 cameraManager.capturePreview(canvas);
85 Rect frame = cameraManager.getFramingRect();
86 int width = canvas.getBitmapWidth();
87 int height = canvas.getBitmapHeight();
89 // Draw the exterior (i.e. outside the framing rect) as half darkened
90 Paint paint = new Paint();
91 paint.setColor(Color.BLACK);
93 Rect box = new Rect(0, 0, width, frame.top);
94 canvas.drawRect(box, paint);
95 box.set(0, frame.top, frame.left, frame.bottom + 1);
96 canvas.drawRect(box, paint);
97 box.set(frame.right + 1, frame.top, width, frame.bottom + 1);
98 canvas.drawRect(box, paint);
99 box.set(0, frame.bottom + 1, width, height);
100 canvas.drawRect(box, paint);
102 // Draw a two pixel solid black border inside the framing rect
104 box.set(frame.left, frame.top, frame.right + 1, frame.top + 2);
105 canvas.drawRect(box, paint);
106 box.set(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1);
107 canvas.drawRect(box, paint);
108 box.set(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1);
109 canvas.drawRect(box, paint);
110 box.set(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1);
111 canvas.drawRect(box, paint);
113 // Draw a red "laser scanner" line through the middle
114 paint.setColor(Color.RED);
115 paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
116 int middle = frame.height() / 2 + frame.top;
117 box.set(frame.left + 2, middle - 1, frame.right - 1, middle + 2);
118 canvas.drawRect(box, paint);
120 surfaceHolder.unlockCanvasAndPost(canvas);
122 // This cheap animation is tied to the rate at which we pull previews from the camera.
123 scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
128 * Draw a line for 1D barcodes (which return two points) or otherwise a set of points returned
129 * from the decoder to indicate what we found.
130 * TODO(dswitkin): It might be nice to clear the framing rect and zoom in on the actual still that
131 * was captured, then paint the green points on it. This would also clear the red scanner line
132 * which doesn't make sense after the capture.
134 * @param resultPoints An array of points from the decoder, whose coordinates are expressed
135 * relative to the still image from the camera.
137 public void drawResultPoints(ResultPoint[] resultPoints) {
139 Canvas canvas = surfaceHolder.lockCanvas();
140 Paint paint = new Paint();
141 paint.setColor(Color.GREEN);
144 Point[] points = cameraManager.convertResultPoints(resultPoints);
145 if (points.length == 2) {
146 paint.setStrokeWidth(4);
147 canvas.drawLine(points[0].x, points[0].y, points[1].x, points[1].y, paint);
149 paint.setStrokeWidth(10);
150 for (int x = 0; x < points.length; x++) {
151 canvas.drawPoint(points[x].x, points[x].y, paint);
155 surfaceHolder.unlockCanvasAndPost(canvas);