2 * Copyright (C) 2010 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.camera;
19 import java.util.regex.Pattern;
21 import android.content.Context;
22 import android.graphics.Point;
23 import android.hardware.Camera;
24 import android.util.Log;
25 import android.view.Display;
26 import android.view.WindowManager;
28 final class CameraConfigurationManager {
30 private static final String TAG = CameraConfigurationManager.class.getSimpleName();
32 private static final int TEN_DESIRED_ZOOM = 27;
33 private static final int DESIRED_SHARPNESS = 30;
35 private static final Pattern COMMA_PATTERN = Pattern.compile(",");
37 private final Context context;
38 private Point screenResolution;
39 private Point cameraResolution;
40 private int previewFormat;
41 private String previewFormatString;
43 CameraConfigurationManager(Context context) {
44 this.context = context;
48 * Reads, one time, values from the camera that are needed by the app.
50 void initFromCameraParameters(Camera camera) {
51 Camera.Parameters parameters = camera.getParameters();
52 previewFormat = parameters.getPreviewFormat();
53 previewFormatString = parameters.get("preview-format");
54 Log.v(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString);
55 WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
56 Display display = manager.getDefaultDisplay();
57 screenResolution = new Point(display.getWidth(), display.getHeight());
58 Log.v(TAG, "Screen resolution: " + screenResolution);
59 cameraResolution = getCameraResolution(parameters, screenResolution);
60 Log.v(TAG, "Camera resolution: " + screenResolution);
64 * Sets the camera up to take preview images which are used for both preview and decoding.
65 * We detect the preview format here so that buildLuminanceSource() can build an appropriate
66 * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
67 * and the planar Y can be used for barcode scanning without a copy in some cases.
69 void setDesiredCameraParameters(Camera camera) {
70 Camera.Parameters parameters = camera.getParameters();
71 Log.v(TAG, "Setting preview size: " + cameraResolution);
72 parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
75 //setSharpness(parameters);
76 camera.setParameters(parameters);
79 Point getCameraResolution() {
80 return cameraResolution;
83 Point getScreenResolution() {
84 return screenResolution;
87 int getPreviewFormat() {
91 String getPreviewFormatString() {
92 return previewFormatString;
95 private static Point getCameraResolution(Camera.Parameters parameters, Point screenResolution) {
97 String previewSizeValueString = parameters.get("preview-size-values");
99 if (previewSizeValueString == null) {
100 previewSizeValueString = parameters.get("preview-size-value");
103 Point cameraResolution = null;
105 if (previewSizeValueString != null) {
106 Log.v(TAG, "preview-size-values parameter: " + previewSizeValueString);
107 cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
110 if (cameraResolution == null) {
111 // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
112 cameraResolution = new Point(
113 (screenResolution.x >> 3) << 3,
114 (screenResolution.y >> 3) << 3);
117 return cameraResolution;
120 private static Point findBestPreviewSizeValue(String previewSizeValueString, Point screenResolution) {
123 int diff = Integer.MAX_VALUE;
124 for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {
126 previewSize = previewSize.trim();
127 int dimPosition = previewSize.indexOf('x');
128 if (dimPosition < 0) {
129 Log.w(TAG, "Bad preview-size: " + previewSize);
136 newX = Integer.parseInt(previewSize.substring(0, dimPosition));
137 newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
138 } catch (NumberFormatException nfe) {
139 Log.w(TAG, "Bad preview-size: " + previewSize);
143 int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
148 } else if (newDiff < diff) {
156 if (bestX > 0 && bestY > 0) {
157 return new Point(bestX, bestY);
162 private static int findBestMotZoomValue(CharSequence stringValues, int tenDesiredZoom) {
163 int tenBestValue = 0;
164 for (String stringValue : COMMA_PATTERN.split(stringValues)) {
165 stringValue = stringValue.trim();
168 value = Double.parseDouble(stringValue);
169 } catch (NumberFormatException nfe) {
170 return tenDesiredZoom;
172 int tenValue = (int) (10.0 * value);
173 if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) {
174 tenBestValue = tenValue;
180 private void setFlash(Camera.Parameters parameters) {
181 // FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
182 parameters.set("flash-value", 2);
183 // This is the standard setting to turn the flash off that all devices should honor.
184 parameters.set("flash-mode", "off");
187 private void setZoom(Camera.Parameters parameters) {
189 String zoomSupportedString = parameters.get("zoom-supported");
190 if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
194 int tenDesiredZoom = TEN_DESIRED_ZOOM;
196 String maxZoomString = parameters.get("max-zoom");
197 if (maxZoomString != null) {
199 int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
200 if (tenDesiredZoom > tenMaxZoom) {
201 tenDesiredZoom = tenMaxZoom;
203 } catch (NumberFormatException nfe) {
204 Log.w(TAG, "Bad max-zoom: " + maxZoomString);
208 String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
209 if (takingPictureZoomMaxString != null) {
211 int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
212 if (tenDesiredZoom > tenMaxZoom) {
213 tenDesiredZoom = tenMaxZoom;
215 } catch (NumberFormatException nfe) {
216 Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString);
220 String motZoomValuesString = parameters.get("mot-zoom-values");
221 if (motZoomValuesString != null) {
222 tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
225 String motZoomStepString = parameters.get("mot-zoom-step");
226 if (motZoomStepString != null) {
228 double motZoomStep = Double.parseDouble(motZoomStepString.trim());
229 int tenZoomStep = (int) (10.0 * motZoomStep);
230 if (tenZoomStep > 1) {
231 tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
233 } catch (NumberFormatException nfe) {
238 // Set zoom. This helps encourage the user to pull back.
239 // Some devices like the Behold have a zoom parameter
240 if (maxZoomString != null || motZoomValuesString != null) {
241 parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
244 // Most devices, like the Hero, appear to expose this zoom parameter.
245 // It takes on values like "27" which appears to mean 2.7x zoom
246 if (takingPictureZoomMaxString != null) {
247 parameters.set("taking-picture-zoom", tenDesiredZoom);
252 private void setSharpness(Camera.Parameters parameters) {
254 int desiredSharpness = DESIRED_SHARPNESS;
256 String maxSharpnessString = parameters.get("sharpness-max");
257 if (maxSharpnessString != null) {
259 int maxSharpness = Integer.parseInt(maxSharpnessString);
260 if (desiredSharpness > maxSharpness) {
261 desiredSharpness = maxSharpness;
263 } catch (NumberFormatException nfe) {
264 Log.w(TAG, "Bad sharpness-max: " + maxSharpnessString);
268 parameters.set("sharpness", desiredSharpness);