/* * Copyright (C) 2009 Muthu Ramadoss. All rights reserved. * * Modified from Zxing project to suit Books-Exchange requirements. * Original source from Zxing - http://code.google.com/p/zxing/ */ /* * 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.androidrocks.bex.zxing.client.android; import com.google.zxing.ResultPoint; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; import android.hardware.Camera; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.Display; import android.view.SurfaceHolder; import android.view.WindowManager; import java.io.IOException; /** * This object wraps the Camera service object and expects to be the only one talking to it. The * implementation encapsulates the steps needed to take preview-sized images, which are used for * both preview and decoding. */ final class CameraManager { private static final String TAG = "CameraManager"; private static CameraManager mCameraManager; private Camera mCamera; private final Context mContext; private Point mScreenResolution; private Rect mFramingRect; private Handler mPreviewHandler; private int mPreviewMessage; private Handler mAutoFocusHandler; private int mAutoFocusMessage; private boolean mInitialized; private boolean mPreviewing; public static void init(Context context) { if (mCameraManager == null) { mCameraManager = new CameraManager(context); } } public static CameraManager get() { return mCameraManager; } private CameraManager(Context context) { mContext = context; mCamera = null; mInitialized = false; mPreviewing = false; } public void openDriver(SurfaceHolder holder) throws IOException { if (mCamera == null) { mCamera = Camera.open(); mCamera.setPreviewDisplay(holder); if (!mInitialized) { mInitialized = true; getScreenResolution(); } setCameraParameters(); } } public void closeDriver() { if (mCamera != null) { mCamera.release(); mCamera = null; } } public void startPreview() { if (mCamera != null && !mPreviewing) { mCamera.startPreview(); mPreviewing = true; } } public void stopPreview() { if (mCamera != null && mPreviewing) { mCamera.setPreviewCallback(null); mCamera.stopPreview(); mPreviewHandler = null; mAutoFocusHandler = null; mPreviewing = false; } } /** * A single preview frame will be returned to the handler supplied. The data will arrive as byte[] * in the message.obj field, with width and height encoded as message.arg1 and message.arg2, * respectively. * * @param handler The handler to send the message to. * @param message The what field of the message to be sent. */ public void requestPreviewFrame(Handler handler, int message) { if (mCamera != null && mPreviewing) { mPreviewHandler = handler; mPreviewMessage = message; mCamera.setOneShotPreviewCallback(previewCallback); } } public void requestAutoFocus(Handler handler, int message) { if (mCamera != null && mPreviewing) { mAutoFocusHandler = handler; mAutoFocusMessage = message; mCamera.autoFocus(autoFocusCallback); } } /** * Calculates the framing rect which the UI should draw to show the user where to place the * barcode. The actual captured image should be a bit larger than indicated because they might * frame the shot too tightly. This target helps with alignment as well as forces the user to hold * the device far enough away to ensure the image will be in focus. * * @return The rectangle to draw on screen in window coordinates. */ public Rect getFramingRect() { if (mFramingRect == null) { int size = (mScreenResolution.x < mScreenResolution.y ? mScreenResolution.x : mScreenResolution.y) * 3 / 4; int leftOffset = (mScreenResolution.x - size) / 2; int topOffset = (mScreenResolution.y - size) / 2; mFramingRect = new Rect(leftOffset, topOffset, leftOffset + size, topOffset + size); Log.v(TAG, "Calculated framing rect: " + mFramingRect); } return mFramingRect; } /** * Converts the result points from still resolution coordinates to screen coordinates. * * @param points The points returned by the Reader subclass through Result.getResultPoints(). * @return An array of Points scaled to the size of the framing rect and offset appropriately * so they can be drawn in screen coordinates. */ public Point[] convertResultPoints(ResultPoint[] points) { Rect frame = getFramingRect(); int count = points.length; Point[] output = new Point[count]; for (int x = 0; x < count; x++) { output[x] = new Point(); output[x].x = frame.left + (int) (points[x].getX() + 0.5f); output[x].y = frame.top + (int) (points[x].getY() + 0.5f); } return output; } /** * Preview frames are delivered here, which we pass on to the registered handler. Make sure to * clear the handler so it will only receive one message. */ private final Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() { public void onPreviewFrame(byte[] data, Camera camera) { if (mPreviewHandler != null) { Message message = mPreviewHandler.obtainMessage(mPreviewMessage, mScreenResolution.x, mScreenResolution.y, data); message.sendToTarget(); mPreviewHandler = null; } } }; private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { if (mAutoFocusHandler != null) { Message message = mAutoFocusHandler.obtainMessage(mAutoFocusMessage, success); // Simulate continuous autofocus by sending a focus request every 1.5 seconds. mAutoFocusHandler.sendMessageDelayed(message, 1500L); mAutoFocusHandler = null; } } }; /** * Sets the camera up to take preview images which are used for both preview and decoding. We're * counting on the default YUV420 semi-planar data. If that changes in the future, we'll need to * specify it explicitly with setPreviewFormat(). */ private void setCameraParameters() { Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(mScreenResolution.x, mScreenResolution.y); // Disables the built-in flash if present. Hopefully devices will honor this setting. parameters.set("flash-mode", "off"); mCamera.setParameters(parameters); Log.v(TAG, "Setting params for preview: width " + mScreenResolution.x + " height " + mScreenResolution.y); } private Point getScreenResolution() { if (mScreenResolution == null) { WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); Display display = manager.getDefaultDisplay(); mScreenResolution = new Point(display.getWidth(), display.getHeight()); } return mScreenResolution; } }