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 android.content.Context;
20 import android.graphics.Point;
21 import android.hardware.Camera;
22 import android.os.Build;
23 import android.util.Log;
24 import android.view.Display;
25 import android.view.WindowManager;
27 import java.util.regex.Pattern;
29 final class CameraConfigurationManager {
31 private static final String TAG = CameraConfigurationManager.class.getSimpleName();
33 private static final int TEN_DESIRED_ZOOM = 27;
34 private static final int DESIRED_SHARPNESS = 30;
36 private static final Pattern COMMA_PATTERN = Pattern.compile(",");
38 private final Context context;
39 private Point screenResolution;
40 private Point cameraResolution;
41 private int previewFormat;
42 private String previewFormatString;
44 CameraConfigurationManager(Context context) {
45 this.context = context;
49 * Reads, one time, values from the camera that are needed by the app.
51 void initFromCameraParameters(Camera camera) {
52 Camera.Parameters parameters = camera.getParameters();
53 previewFormat = parameters.getPreviewFormat();
54 previewFormatString = parameters.get("preview-format");
55 Log.d(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString);
56 WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
57 Display display = manager.getDefaultDisplay();
58 screenResolution = new Point(display.getWidth(), display.getHeight());
59 Log.d(TAG, "Screen resolution: " + screenResolution);
60 cameraResolution = getCameraResolution(parameters, screenResolution);
61 Log.d(TAG, "Camera resolution: " + screenResolution);
65 * Sets the camera up to take preview images which are used for both preview and decoding.
66 * We detect the preview format here so that buildLuminanceSource() can build an appropriate
67 * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
68 * and the planar Y can be used for barcode scanning without a copy in some cases.
70 void setDesiredCameraParameters(Camera camera) {
71 Camera.Parameters parameters = camera.getParameters();
72 Log.d(TAG, "Setting preview size: " + cameraResolution);
73 parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
76 //setSharpness(parameters);
77 camera.setParameters(parameters);
80 Point getCameraResolution() {
81 return cameraResolution;
84 Point getScreenResolution() {
85 return screenResolution;
88 int getPreviewFormat() {
92 String getPreviewFormatString() {
93 return previewFormatString;
96 private static Point getCameraResolution(Camera.Parameters parameters, Point screenResolution) {
98 String previewSizeValueString = parameters.get("preview-size-values");
100 if (previewSizeValueString == null) {
101 previewSizeValueString = parameters.get("preview-size-value");
104 Point cameraResolution = null;
106 if (previewSizeValueString != null) {
107 Log.d(TAG, "preview-size-values parameter: " + previewSizeValueString);
108 cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
111 if (cameraResolution == null) {
112 // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
113 cameraResolution = new Point(
114 (screenResolution.x >> 3) << 3,
115 (screenResolution.y >> 3) << 3);
118 return cameraResolution;
121 private static Point findBestPreviewSizeValue(CharSequence previewSizeValueString, Point screenResolution) {
124 int diff = Integer.MAX_VALUE;
125 for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {
127 previewSize = previewSize.trim();
128 int dimPosition = previewSize.indexOf('x');
129 if (dimPosition < 0) {
130 Log.w(TAG, "Bad preview-size: " + previewSize);
137 newX = Integer.parseInt(previewSize.substring(0, dimPosition));
138 newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
139 } catch (NumberFormatException nfe) {
140 Log.w(TAG, "Bad preview-size: " + previewSize);
144 int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
149 } else if (newDiff < diff) {
157 if (bestX > 0 && bestY > 0) {
158 return new Point(bestX, bestY);
163 private static int findBestMotZoomValue(CharSequence stringValues, int tenDesiredZoom) {
164 int tenBestValue = 0;
165 for (String stringValue : COMMA_PATTERN.split(stringValues)) {
166 stringValue = stringValue.trim();
169 value = Double.parseDouble(stringValue);
170 } catch (NumberFormatException nfe) {
171 return tenDesiredZoom;
173 int tenValue = (int) (10.0 * value);
174 if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) {
175 tenBestValue = tenValue;
181 private void setFlash(Camera.Parameters parameters) {
182 // FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
183 // And this is a hack-hack to work around a different value on the Behold II
184 // Restrict Behold II check to Cupcake, per Samsung's advice
185 if (Build.MODEL.contains("Behold II") &&
186 CameraManager.SDK_INT == Build.VERSION_CODES.CUPCAKE) {
187 parameters.set("flash-value", 1);
189 parameters.set("flash-value", 2);
191 // This is the standard setting to turn the flash off that all devices should honor.
192 parameters.set("flash-mode", "off");
195 private void setZoom(Camera.Parameters parameters) {
197 String zoomSupportedString = parameters.get("zoom-supported");
198 if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
202 int tenDesiredZoom = TEN_DESIRED_ZOOM;
204 String maxZoomString = parameters.get("max-zoom");
205 if (maxZoomString != null) {
207 int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
208 if (tenDesiredZoom > tenMaxZoom) {
209 tenDesiredZoom = tenMaxZoom;
211 } catch (NumberFormatException nfe) {
212 Log.w(TAG, "Bad max-zoom: " + maxZoomString);
216 String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
217 if (takingPictureZoomMaxString != null) {
219 int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
220 if (tenDesiredZoom > tenMaxZoom) {
221 tenDesiredZoom = tenMaxZoom;
223 } catch (NumberFormatException nfe) {
224 Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString);
228 String motZoomValuesString = parameters.get("mot-zoom-values");
229 if (motZoomValuesString != null) {
230 tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
233 String motZoomStepString = parameters.get("mot-zoom-step");
234 if (motZoomStepString != null) {
236 double motZoomStep = Double.parseDouble(motZoomStepString.trim());
237 int tenZoomStep = (int) (10.0 * motZoomStep);
238 if (tenZoomStep > 1) {
239 tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
241 } catch (NumberFormatException nfe) {
246 // Set zoom. This helps encourage the user to pull back.
247 // Some devices like the Behold have a zoom parameter
248 if (maxZoomString != null || motZoomValuesString != null) {
249 parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
252 // Most devices, like the Hero, appear to expose this zoom parameter.
253 // It takes on values like "27" which appears to mean 2.7x zoom
254 if (takingPictureZoomMaxString != null) {
255 parameters.set("taking-picture-zoom", tenDesiredZoom);
260 private void setSharpness(Camera.Parameters parameters) {
262 int desiredSharpness = DESIRED_SHARPNESS;
264 String maxSharpnessString = parameters.get("sharpness-max");
265 if (maxSharpnessString != null) {
267 int maxSharpness = Integer.parseInt(maxSharpnessString);
268 if (desiredSharpness > maxSharpness) {
269 desiredSharpness = maxSharpness;
271 } catch (NumberFormatException nfe) {
272 Log.w(TAG, "Bad sharpness-max: " + maxSharpnessString);
276 parameters.set("sharpness", desiredSharpness);