2 * Copyright (C) 2008 ZXing authors
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 android.content.Context;
20 import android.graphics.Point;
21 import android.graphics.Rect;
22 import android.hardware.Camera;
23 import android.os.Handler;
24 import android.os.Message;
25 import android.util.Log;
26 import android.view.Display;
27 import android.view.SurfaceHolder;
28 import android.view.WindowManager;
29 import com.google.zxing.ResultPoint;
32 * This object wraps the Camera service object and expects to be the only one talking to it. The
33 * implementation encapsulates the steps needed to take preview-sized images, which are used for
34 * both preview and decoding.
36 final class CameraManager {
38 private static final String TAG = "CameraManager";
40 private static CameraManager mCameraManager;
41 private Camera mCamera;
42 private final Context mContext;
43 private Point mScreenResolution;
44 private Rect mFramingRect;
45 private Handler mPreviewHandler;
46 private int mPreviewMessage;
47 private Handler mAutoFocusHandler;
48 private int mAutoFocusMessage;
49 private boolean mInitialized;
50 private boolean mPreviewing;
52 public static void init(Context context) {
53 if (mCameraManager == null) {
54 mCameraManager = new CameraManager(context);
58 public static CameraManager get() {
59 return mCameraManager;
62 private CameraManager(Context context) {
69 public void openDriver(SurfaceHolder holder) {
70 if (mCamera == null) {
71 mCamera = Camera.open();
72 mCamera.setPreviewDisplay(holder);
76 getScreenResolution();
79 setCameraParameters();
83 public void closeDriver() {
84 if (mCamera != null) {
90 public void startPreview() {
91 if (mCamera != null && !mPreviewing) {
92 mCamera.startPreview();
97 public void stopPreview() {
98 if (mCamera != null && mPreviewing) {
99 mCamera.setPreviewCallback(null);
100 mCamera.stopPreview();
101 mPreviewHandler = null;
102 mAutoFocusHandler = null;
108 * A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
109 * in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
112 * @param handler The handler to send the message to.
113 * @param message The what field of the message to be sent.
115 public void requestPreviewFrame(Handler handler, int message) {
116 if (mCamera != null && mPreviewing) {
117 mPreviewHandler = handler;
118 mPreviewMessage = message;
119 mCamera.setPreviewCallback(previewCallback);
123 public void requestAutoFocus(Handler handler, int message) {
124 if (mCamera != null && mPreviewing) {
125 mAutoFocusHandler = handler;
126 mAutoFocusMessage = message;
127 mCamera.autoFocus(autoFocusCallback);
132 * Calculates the framing rect which the UI should draw to show the user where to place the
133 * barcode. The actual captured image should be a bit larger than indicated because they might
134 * frame the shot too tightly. This target helps with alignment as well as forces the user to hold
135 * the device far enough away to ensure the image will be in focus.
137 * @return The rectangle to draw on screen in window coordinates.
139 public Rect getFramingRect() {
140 if (mFramingRect == null) {
141 int size = ((mScreenResolution.x < mScreenResolution.y) ? mScreenResolution.x :
142 mScreenResolution.y) * 3 / 4;
143 int leftOffset = (mScreenResolution.x - size) / 2;
144 int topOffset = (mScreenResolution.y - size) / 2;
145 mFramingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size);
146 Log.v(TAG, "Calculated framing rect: " + mFramingRect);
152 * Converts the result points from still resolution coordinates to screen coordinates.
154 * @param points The points returned by the Reader subclass through Result.getResultPoints().
155 * @return An array of Points scaled to the size of the framing rect and offset appropriately
156 * so they can be drawn in screen coordinates.
158 public Point[] convertResultPoints(ResultPoint[] points) {
159 Rect frame = getFramingRect();
160 int count = points.length;
161 Point[] output = new Point[count];
162 for (int x = 0; x < count; x++) {
163 output[x] = new Point();
164 output[x].x = frame.left + (int) (points[x].getX() + 0.5f);
165 output[x].y = frame.top + (int) (points[x].getY() + 0.5f);
171 * Preview frames are delivered here, which we pass on to the registered handler. Make sure to
172 * clear the handler so it will only receive one message.
174 private final Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
175 public void onPreviewFrame(byte[] data, Camera camera) {
176 camera.setPreviewCallback(null);
177 if (mPreviewHandler != null) {
178 Message message = mPreviewHandler.obtainMessage(mPreviewMessage, mScreenResolution.x,
179 mScreenResolution.y, data);
180 message.sendToTarget();
181 mPreviewHandler = null;
186 private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
187 public void onAutoFocus(boolean success, Camera camera) {
188 if (mAutoFocusHandler != null) {
189 Message message = mAutoFocusHandler.obtainMessage(mAutoFocusMessage, success);
190 // Simulate continuous autofocus by sending a focus request every 1.5 seconds.
191 mAutoFocusHandler.sendMessageDelayed(message, 1500);
192 mAutoFocusHandler = null;
198 * Sets the camera up to take preview images which are used for both preview and decoding. We're
199 * counting on the default YUV420 semi-planar data. If that changes in the future, we'll need to
200 * specify it explicitly with setPreviewFormat().
202 private void setCameraParameters() {
203 Camera.Parameters parameters = mCamera.getParameters();
204 parameters.setPreviewSize(mScreenResolution.x, mScreenResolution.y);
205 mCamera.setParameters(parameters);
206 Log.v(TAG, "Setting params for preview: width " + mScreenResolution.x + " height " +
207 mScreenResolution.y);
210 private Point getScreenResolution() {
211 if (mScreenResolution == null) {
212 WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
213 Display display = manager.getDefaultDisplay();
214 mScreenResolution = new Point(display.getWidth(), display.getHeight());
216 return mScreenResolution;