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 screenResolution = getScreenResolution();
56 cameraResolution = getCameraResolution(parameters);
60 * Sets the camera up to take preview images which are used for both preview and decoding.
61 * We detect the preview format here so that buildLuminanceSource() can build an appropriate
62 * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
63 * and the planar Y can be used for barcode scanning without a copy in some cases.
65 void setDesiredCameraParameters(Camera camera) {
66 Camera.Parameters parameters = camera.getParameters();
67 Log.v(TAG, "Setting preview size: " + cameraResolution.x + ", " + cameraResolution.y);
68 parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
71 //setSharpness(parameters);
72 camera.setParameters(parameters);
75 Point getCameraResolution() {
76 return cameraResolution;
79 int getPreviewFormat() {
83 String getPreviewFormatString() {
84 return previewFormatString;
87 private Point getScreenResolution() {
88 WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
89 Display display = manager.getDefaultDisplay();
90 return new Point(display.getWidth(), display.getHeight());
93 private Point getCameraResolution(Camera.Parameters parameters) {
95 String previewSizeValueString = parameters.get("preview-size-values");
97 if (previewSizeValueString == null) {
98 previewSizeValueString = parameters.get("preview-size-value");
101 Point cameraResolution = null;
103 if (previewSizeValueString != null) {
104 Log.v(TAG, "preview-size parameter: " + previewSizeValueString);
105 cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
108 if (cameraResolution == null) {
109 // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
110 cameraResolution = new Point(
111 (screenResolution.x >> 3) << 3,
112 (screenResolution.y >> 3) << 3);
115 return cameraResolution;
118 private static Point findBestPreviewSizeValue(String previewSizeValueString, Point screenResolution) {
121 int diff = Integer.MAX_VALUE;
122 for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {
124 previewSize = previewSize.trim();
125 int dimPosition = previewSize.indexOf('x');
126 if (dimPosition < 0) {
127 Log.w(TAG, "Bad preview-size: " + previewSize);
134 newX = Integer.parseInt(previewSize.substring(0, dimPosition));
135 newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
136 } catch (NumberFormatException nfe) {
137 Log.w(TAG, "Bad preview-size: " + previewSize);
141 int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
146 } else if (newDiff < diff) {
154 if (bestX > 0 && bestY > 0) {
155 return new Point(bestX, bestY);
160 private static int findBestMotZoomValue(String stringValues, int tenDesiredZoom) {
161 int tenBestValue = 0;
162 for (String stringValue : COMMA_PATTERN.split(stringValues)) {
163 stringValue = stringValue.trim();
166 value = Double.parseDouble(stringValue);
167 } catch (NumberFormatException nfe) {
168 return tenDesiredZoom;
170 int tenValue = (int) (10.0 * value);
171 if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) {
172 tenBestValue = tenValue;
178 private void setFlash(Camera.Parameters parameters) {
179 // FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
180 parameters.set("flash-value", 2);
181 // This is the standard setting to turn the flash off that all devices should honor.
182 parameters.set("flash-mode", "off");
185 private void setZoom(Camera.Parameters parameters) {
187 String zoomSupportedString = parameters.get("zoom-supported");
188 if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
192 int tenDesiredZoom = TEN_DESIRED_ZOOM;
194 String maxZoomString = parameters.get("max-zoom");
195 if (maxZoomString != null) {
197 int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
198 if (tenDesiredZoom > tenMaxZoom) {
199 tenDesiredZoom = tenMaxZoom;
201 } catch (NumberFormatException nfe) {
202 Log.w(TAG, "Bad max-zoom: " + maxZoomString);
206 String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
207 if (takingPictureZoomMaxString != null) {
209 int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
210 if (tenDesiredZoom > tenMaxZoom) {
211 tenDesiredZoom = tenMaxZoom;
213 } catch (NumberFormatException nfe) {
214 Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString);
218 String motZoomValuesString = parameters.get("mot-zoom-values");
219 if (motZoomValuesString != null) {
220 tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
223 String motZoomStepString = parameters.get("mot-zoom-step");
224 if (motZoomStepString != null) {
226 double motZoomStep = Double.parseDouble(motZoomStepString.trim());
227 int tenZoomStep = (int) (10.0 * motZoomStep);
228 if (tenZoomStep > 1) {
229 tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
231 } catch (NumberFormatException nfe) {
236 // Set zoom. This helps encourage the user to pull back.
237 // Some devices like the Behold have a zoom parameter
238 if (maxZoomString != null || motZoomValuesString != null) {
239 parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
242 // Most devices, like the Hero, appear to expose this zoom parameter.
243 // It takes on values like "27" which appears to mean 2.7x zoom
244 if (takingPictureZoomMaxString != null) {
245 parameters.set("taking-picture-zoom", tenDesiredZoom);
250 private void setSharpness(Camera.Parameters parameters) {
252 int desiredSharpness = DESIRED_SHARPNESS;
254 String maxSharpnessString = parameters.get("sharpness-max");
255 if (maxSharpnessString != null) {
257 int maxSharpness = Integer.parseInt(maxSharpnessString);
258 if (desiredSharpness > maxSharpness) {
259 desiredSharpness = maxSharpness;
261 } catch (NumberFormatException nfe) {
262 Log.w(TAG, "Bad sharpness-max: " + maxSharpnessString);
266 parameters.set("sharpness", desiredSharpness);