From 9e9e5671d9de5e7d73322bca50d932892e28aa7f Mon Sep 17 00:00:00 2001 From: srowen Date: Wed, 16 Nov 2011 10:39:50 +0000 Subject: [PATCH] Remove some pre-Eclair code, update camera parameters handling to use 2.x APIs git-svn-id: https://zxing.googlecode.com/svn/trunk@2038 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- .../camera/CameraConfigurationManager.java | 239 ++++++------------ .../client/android/camera/CameraManager.java | 66 +---- .../android/camera/FlashlightManager.java | 141 ----------- .../android/camera/PreviewCallback.java | 7 +- 4 files changed, 85 insertions(+), 368 deletions(-) delete mode 100644 android/src/com/google/zxing/client/android/camera/FlashlightManager.java diff --git a/android/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java b/android/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java index 8c253612d..7a393e359 100644 --- a/android/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java +++ b/android/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java @@ -17,14 +17,17 @@ package com.google.zxing.client.android.camera; import android.content.Context; +import android.content.SharedPreferences; import android.graphics.Point; import android.hardware.Camera; -import android.os.Build; +import android.preference.PreferenceManager; import android.util.Log; import android.view.Display; import android.view.WindowManager; -import java.util.regex.Pattern; +import com.google.zxing.client.android.PreferencesActivity; + +import java.util.Collection; /** * A class which deals with reading, parsing, and setting the camera parameters which are used to @@ -32,15 +35,12 @@ import java.util.regex.Pattern; */ final class CameraConfigurationManager { - private static final String TAG = CameraConfigurationManager.class.getSimpleName(); - private static final int TEN_DESIRED_ZOOM = 27; - private static final Pattern COMMA_PATTERN = Pattern.compile(","); + private static final String TAG = "CameraConfiguration"; + private static final int MIN_PREVIEW_PIXELS = 320 * 240; // small screen private final Context context; private Point screenResolution; private Point cameraResolution; - private int previewFormat; - private String previewFormatString; CameraConfigurationManager(Context context) { this.context = context; @@ -51,29 +51,33 @@ final class CameraConfigurationManager { */ void initFromCameraParameters(Camera camera) { Camera.Parameters parameters = camera.getParameters(); - previewFormat = parameters.getPreviewFormat(); - previewFormatString = parameters.get("preview-format"); - Log.d(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString); WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = manager.getDefaultDisplay(); screenResolution = new Point(display.getWidth(), display.getHeight()); - Log.d(TAG, "Screen resolution: " + screenResolution); - cameraResolution = getCameraResolution(parameters, screenResolution); - Log.d(TAG, "Camera resolution: " + cameraResolution); + Log.i(TAG, "Screen resolution: " + screenResolution); + cameraResolution = findBestPreviewSizeValue(parameters, screenResolution, false); + Log.i(TAG, "Camera resolution: " + cameraResolution); } - /** - * Sets the camera up to take preview images which are used for both preview and decoding. - * We detect the preview format here so that buildLuminanceSource() can build an appropriate - * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest, - * and the planar Y can be used for barcode scanning without a copy in some cases. - */ void setDesiredCameraParameters(Camera camera) { Camera.Parameters parameters = camera.getParameters(); - Log.d(TAG, "Setting preview size: " + cameraResolution); + + if (parameters == null) { + Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration."); + return; + } + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + + initializeTorch(parameters, prefs); + String focusMode = findSettableValue(parameters.getSupportedFocusModes(), + Camera.Parameters.FOCUS_MODE_AUTO, + Camera.Parameters.FOCUS_MODE_MACRO); + if (focusMode != null) { + parameters.setFocusMode(focusMode); + } + parameters.setPreviewSize(cameraResolution.x, cameraResolution.y); - setFlash(parameters); - setZoom(parameters); camera.setParameters(parameters); } @@ -85,166 +89,81 @@ final class CameraConfigurationManager { return screenResolution; } - int getPreviewFormat() { - return previewFormat; + void setTorch(Camera camera, boolean newSetting) { + Camera.Parameters parameters = camera.getParameters(); + doSetTorch(parameters, newSetting); + camera.setParameters(parameters); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + boolean currentSetting = prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false); + if (currentSetting != newSetting) { + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(PreferencesActivity.KEY_FRONT_LIGHT, newSetting); + editor.commit(); + } } - String getPreviewFormatString() { - return previewFormatString; + private static void initializeTorch(Camera.Parameters parameters, SharedPreferences prefs) { + boolean currentSetting = prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false); + doSetTorch(parameters, currentSetting); } - private static Point getCameraResolution(Camera.Parameters parameters, Point screenResolution) { - String previewSizeValueString = parameters.get("preview-size-values"); - - // This string is wrong but was seen on the Sony Xperia. - if (previewSizeValueString == null) { - previewSizeValueString = parameters.get("preview-size-value"); + private static void doSetTorch(Camera.Parameters parameters, boolean newSetting) { + String flashMode; + if (newSetting) { + flashMode = findSettableValue(parameters.getSupportedFlashModes(), + Camera.Parameters.FLASH_MODE_TORCH, + Camera.Parameters.FLASH_MODE_ON); + } else { + flashMode = findSettableValue(parameters.getSupportedFlashModes(), + Camera.Parameters.FLASH_MODE_OFF); } - - Point cameraResolution = null; - if (previewSizeValueString != null) { - Log.d(TAG, "preview-size-values parameter: " + previewSizeValueString); - cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution); + if (flashMode != null) { + parameters.setFlashMode(flashMode); } - - if (cameraResolution == null) { - // Ensure that the camera resolution is a multiple of 8, as the screen may not be. - cameraResolution = new Point((screenResolution.x >> 3) << 3, (screenResolution.y >> 3) << 3); - } - return cameraResolution; } - private static Point findBestPreviewSizeValue(CharSequence previewSizeValueString, - Point screenResolution) { - int bestX = 0; - int bestY = 0; + private static Point findBestPreviewSizeValue(Camera.Parameters parameters, + Point screenResolution, + boolean portrait) { + Point bestSize = null; int diff = Integer.MAX_VALUE; - for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) { - previewSize = previewSize.trim(); - int dimPosition = previewSize.indexOf('x'); - if (dimPosition < 0) { - Log.w(TAG, "Bad preview-size: " + previewSize); + for (Camera.Size supportedPreviewSize : parameters.getSupportedPreviewSizes()) { + if (supportedPreviewSize.height * supportedPreviewSize.width < MIN_PREVIEW_PIXELS) { continue; } - - int newX; - int newY; - try { - newX = Integer.parseInt(previewSize.substring(0, dimPosition)); - newY = Integer.parseInt(previewSize.substring(dimPosition + 1)); - } catch (NumberFormatException nfe) { - Log.w(TAG, "Bad preview-size: " + previewSize); - continue; - } - - int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y); + int supportedWidth = portrait ? supportedPreviewSize.height : supportedPreviewSize.width; + int supportedHeight = portrait ? supportedPreviewSize.width : supportedPreviewSize.height; + int newDiff = Math.abs(screenResolution.x * supportedHeight - supportedWidth * screenResolution.y); if (newDiff == 0) { - bestX = newX; - bestY = newY; + bestSize = new Point(supportedWidth, supportedHeight); break; - } else if (newDiff < diff) { - bestX = newX; - bestY = newY; + } + if (newDiff < diff) { + bestSize = new Point(supportedWidth, supportedHeight); diff = newDiff; } } - - if (bestX > 0 && bestY > 0) { - return new Point(bestX, bestY); + if (bestSize == null) { + Camera.Size defaultSize = parameters.getPreviewSize(); + bestSize = new Point(defaultSize.width, defaultSize.height); } - return null; + return bestSize; } - private static int findBestMotZoomValue(CharSequence stringValues, int tenDesiredZoom) { - int tenBestValue = 0; - for (String stringValue : COMMA_PATTERN.split(stringValues)) { - stringValue = stringValue.trim(); - double value; - try { - value = Double.parseDouble(stringValue); - } catch (NumberFormatException nfe) { - return tenDesiredZoom; - } - int tenValue = (int) (10.0 * value); - if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) { - tenBestValue = tenValue; - } - } - return tenBestValue; - } - - private void setFlash(Camera.Parameters parameters) { - // This is a hack to turn the flash off on the Samsung Galaxy and the Behold II - // as advised by Samsung, neither of which respected the official parameter. - if (Build.MODEL.contains("Behold II") && CameraManager.SDK_INT == 3) { // 3 = Cupcake - parameters.set("flash-value", 1); - } else { - parameters.set("flash-value", 2); - } - // This is the standard setting to turn the flash off that all devices should honor. - parameters.set("flash-mode", "off"); - } - - private void setZoom(Camera.Parameters parameters) { - String zoomSupportedString = parameters.get("zoom-supported"); - if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) { - return; - } - - int tenDesiredZoom = TEN_DESIRED_ZOOM; - String maxZoomString = parameters.get("max-zoom"); - if (maxZoomString != null) { - try { - int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString)); - if (tenDesiredZoom > tenMaxZoom) { - tenDesiredZoom = tenMaxZoom; + private static String findSettableValue(Collection supportedValues, + String... desiredValues) { + Log.i(TAG, "Supported values: " + supportedValues); + String result = null; + if (supportedValues != null) { + for (String desiredValue : desiredValues) { + if (supportedValues.contains(desiredValue)) { + result = desiredValue; + break; } - } catch (NumberFormatException nfe) { - Log.w(TAG, "Bad max-zoom: " + maxZoomString); } } - - String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max"); - if (takingPictureZoomMaxString != null) { - try { - int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString); - if (tenDesiredZoom > tenMaxZoom) { - tenDesiredZoom = tenMaxZoom; - } - } catch (NumberFormatException nfe) { - Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString); - } - } - - String motZoomValuesString = parameters.get("mot-zoom-values"); - if (motZoomValuesString != null) { - tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom); - } - - String motZoomStepString = parameters.get("mot-zoom-step"); - if (motZoomStepString != null) { - try { - double motZoomStep = Double.parseDouble(motZoomStepString.trim()); - int tenZoomStep = (int) (10.0 * motZoomStep); - if (tenZoomStep > 1) { - tenDesiredZoom -= tenDesiredZoom % tenZoomStep; - } - } catch (NumberFormatException nfe) { - // continue - } - } - - // Sets the zoom which helps encourage the user to pull back. - // Some devices like the Behold have a zoom parameter. - if (maxZoomString != null || motZoomValuesString != null) { - parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0)); - } - - // Most devices, like the Hero, appear to expose this zoom parameter. - // It takes on values like "27" which appears to mean 2.7x zoom. - if (takingPictureZoomMaxString != null) { - parameters.set("taking-picture-zoom", tenDesiredZoom); - } + Log.i(TAG, "Settable value: " + result); + return result; } } diff --git a/android/src/com/google/zxing/client/android/camera/CameraManager.java b/android/src/com/google/zxing/client/android/camera/CameraManager.java index 22d10d36c..c7c521461 100755 --- a/android/src/com/google/zxing/client/android/camera/CameraManager.java +++ b/android/src/com/google/zxing/client/android/camera/CameraManager.java @@ -18,11 +18,9 @@ package com.google.zxing.client.android.camera; import android.content.Context; import android.content.SharedPreferences; -import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.hardware.Camera; -import android.os.Build; import android.os.Handler; import android.preference.PreferenceManager; import android.util.Log; @@ -48,18 +46,6 @@ public final class CameraManager { private static final int MAX_FRAME_WIDTH = 600; private static final int MAX_FRAME_HEIGHT = 400; - static final int SDK_INT; // Later we can use Build.VERSION.SDK_INT - static { - int sdkInt; - try { - sdkInt = Integer.parseInt(Build.VERSION.SDK); - } catch (NumberFormatException nfe) { - // Just to be safe - sdkInt = 10000; - } - SDK_INT = sdkInt; - } - private final Context context; private final CameraConfigurationManager configManager; private Camera camera; @@ -68,7 +54,6 @@ public final class CameraManager { private boolean initialized; private boolean previewing; private boolean reverseImage; - private final boolean useOneShotPreviewCallback; private int requestedFramingRectWidth; private int requestedFramingRectHeight; /** @@ -76,22 +61,13 @@ public final class CameraManager { * clear the handler so it will only receive one message. */ private final PreviewCallback previewCallback; - /** Autofocus callbacks arrive here, and are dispatched to the Handler which requested them. */ private final AutoFocusCallback autoFocusCallback; public CameraManager(Context context) { - this.context = context; this.configManager = new CameraConfigurationManager(context); - - // Camera.setOneShotPreviewCallback() has a race condition in Cupcake, so we use the older - // Camera.setPreviewCallback() on 1.5 and earlier. For Donut and later, we need to use - // the more efficient one shot callback, as the older one can swamp the system and cause it - // to run out of memory. We can't use SDK_INT because it was introduced in the Donut SDK. - useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > 3; // 3 = Cupcake - - previewCallback = new PreviewCallback(configManager, useOneShotPreviewCallback); + previewCallback = new PreviewCallback(configManager); autoFocusCallback = new AutoFocusCallback(); } @@ -125,9 +101,6 @@ public final class CameraManager { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); reverseImage = prefs.getBoolean(PreferencesActivity.KEY_REVERSE_IMAGE, false); - if (prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false)) { - FlashlightManager.enableFlashlight(); - } } /** @@ -135,10 +108,8 @@ public final class CameraManager { */ public void closeDriver() { if (camera != null) { - FlashlightManager.disableFlashlight(); camera.release(); camera = null; - // Make sure to clear these each time we close the camera, so that any scanning rect // requested by intent is forgotten. framingRect = null; @@ -162,9 +133,6 @@ public final class CameraManager { */ public void stopPreview() { if (camera != null && previewing) { - if (!useOneShotPreviewCallback) { - camera.setPreviewCallback(null); - } camera.stopPreview(); previewCallback.setHandler(null, 0); autoFocusCallback.setHandler(null, 0); @@ -184,11 +152,7 @@ public final class CameraManager { Camera theCamera = camera; if (theCamera != null && previewing) { previewCallback.setHandler(handler, message); - if (useOneShotPreviewCallback) { - theCamera.setOneShotPreviewCallback(previewCallback); - } else { - theCamera.setPreviewCallback(previewCallback); - } + theCamera.setOneShotPreviewCallback(previewCallback); } } @@ -201,7 +165,6 @@ public final class CameraManager { public void requestAutoFocus(Handler handler, int message) { if (camera != null && previewing) { autoFocusCallback.setHandler(handler, message); - //Log.d(TAG, "Requesting auto-focus callback"); camera.autoFocus(autoFocusCallback); } } @@ -302,28 +265,9 @@ public final class CameraManager { if (rect == null) { return null; } - int previewFormat = configManager.getPreviewFormat(); - String previewFormatString = configManager.getPreviewFormatString(); - - switch (previewFormat) { - // This is the standard Android format which all devices are REQUIRED to support. - // In theory, it's the only one we should ever care about. - case PixelFormat.YCbCr_420_SP: - // This format has never been seen in the wild, but is compatible as we only care - // about the Y channel, so allow it. - case PixelFormat.YCbCr_422_SP: - return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, - rect.width(), rect.height(), reverseImage); - default: - // The Samsung Moment incorrectly uses this variant instead of the 'sp' version. - // Fortunately, it too has all the Y data up front, so we can read it. - if ("yuv420p".equals(previewFormatString)) { - return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, - rect.width(), rect.height(), reverseImage); - } - } - throw new IllegalArgumentException("Unsupported picture format: " + - previewFormat + '/' + previewFormatString); + // Go ahead and assume it's YUV rather than die. + return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, + rect.width(), rect.height(), reverseImage); } } diff --git a/android/src/com/google/zxing/client/android/camera/FlashlightManager.java b/android/src/com/google/zxing/client/android/camera/FlashlightManager.java deleted file mode 100644 index b5330ba89..000000000 --- a/android/src/com/google/zxing/client/android/camera/FlashlightManager.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2010 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.google.zxing.client.android.camera; - -import android.os.IBinder; -import android.util.Log; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * This class is used to activate the weak light on some camera phones (not flash) - * in order to illuminate surfaces for scanning. There is no official way to do this, - * but, classes which allow access to this function still exist on some devices. - * This therefore proceeds through a great deal of reflection. - * - * See http://almondmendoza.com/2009/01/05/changing-the-screen-brightness-programatically/ and - * http://code.google.com/p/droidled/source/browse/trunk/src/com/droidled/demo/DroidLED.java . - * Thanks to Ryan Alford for pointing out the availability of this class. - */ -final class FlashlightManager { - - private static final String TAG = FlashlightManager.class.getSimpleName(); - - private static final Object iHardwareService; - private static final Method setFlashEnabledMethod; - static { - iHardwareService = getHardwareService(); - Log.v(TAG, "This device does " + (iHardwareService == null ? "not" : "") + " support control of a flashlight"); - setFlashEnabledMethod = getSetFlashEnabledMethod(iHardwareService); - } - - private FlashlightManager() { - } - - private static Object getHardwareService() { - Class serviceManagerClass = maybeForName("android.os.ServiceManager"); - if (serviceManagerClass == null) { - return null; - } - - Method getServiceMethod = maybeGetMethod(serviceManagerClass, "getService", String.class); - if (getServiceMethod == null) { - return null; - } - - Object hardwareService = invoke(getServiceMethod, null, "hardware"); - if (hardwareService == null) { - return null; - } - - Class iHardwareServiceStubClass = maybeForName("android.os.IHardwareService$Stub"); - if (iHardwareServiceStubClass == null) { - return null; - } - - Method asInterfaceMethod = maybeGetMethod(iHardwareServiceStubClass, "asInterface", - IBinder.class); - if (asInterfaceMethod == null) { - return null; - } - - return invoke(asInterfaceMethod, null, hardwareService); - } - - private static Method getSetFlashEnabledMethod(Object iHardwareService) { - if (iHardwareService == null) { - return null; - } - Class proxyClass = iHardwareService.getClass(); - return maybeGetMethod(proxyClass, "setFlashlightEnabled", boolean.class); - } - - private static Class maybeForName(String name) { - try { - return Class.forName(name); - } catch (ClassNotFoundException cnfe) { - // OK - return null; - } catch (RuntimeException re) { - Log.w(TAG, "Unexpected error while finding class " + name, re); - return null; - } - } - - private static Method maybeGetMethod(Class clazz, String name, Class... argClasses) { - try { - return clazz.getMethod(name, argClasses); - } catch (NoSuchMethodException nsme) { - // OK - return null; - } catch (RuntimeException re) { - Log.w(TAG, "Unexpected error while finding method " + name, re); - return null; - } - } - - private static Object invoke(Method method, Object instance, Object... args) { - try { - return method.invoke(instance, args); - } catch (IllegalAccessException e) { - Log.w(TAG, "Unexpected error while invoking " + method, e); - return null; - } catch (InvocationTargetException e) { - Log.w(TAG, "Unexpected error while invoking " + method, e.getCause()); - return null; - } catch (RuntimeException re) { - Log.w(TAG, "Unexpected error while invoking " + method, re); - return null; - } - } - - static void enableFlashlight() { - setFlashlight(true); - } - - static void disableFlashlight() { - setFlashlight(false); - } - - private static void setFlashlight(boolean active) { - if (iHardwareService != null) { - invoke(setFlashEnabledMethod, iHardwareService, active); - } - } - -} diff --git a/android/src/com/google/zxing/client/android/camera/PreviewCallback.java b/android/src/com/google/zxing/client/android/camera/PreviewCallback.java index 5ef70ee81..bbceefa2d 100644 --- a/android/src/com/google/zxing/client/android/camera/PreviewCallback.java +++ b/android/src/com/google/zxing/client/android/camera/PreviewCallback.java @@ -27,13 +27,11 @@ final class PreviewCallback implements Camera.PreviewCallback { private static final String TAG = PreviewCallback.class.getSimpleName(); private final CameraConfigurationManager configManager; - private final boolean useOneShotPreviewCallback; private Handler previewHandler; private int previewMessage; - PreviewCallback(CameraConfigurationManager configManager, boolean useOneShotPreviewCallback) { + PreviewCallback(CameraConfigurationManager configManager) { this.configManager = configManager; - this.useOneShotPreviewCallback = useOneShotPreviewCallback; } void setHandler(Handler previewHandler, int previewMessage) { @@ -44,9 +42,6 @@ final class PreviewCallback implements Camera.PreviewCallback { @Override public void onPreviewFrame(byte[] data, Camera camera) { Point cameraResolution = configManager.getCameraResolution(); - if (!useOneShotPreviewCallback) { - camera.setPreviewCallback(null); - } Handler thePreviewHandler = previewHandler; if (thePreviewHandler != null) { Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,