From c1b1b631705922cfdf3e50a1f7b9d3f92ff7ba70 Mon Sep 17 00:00:00 2001 From: Sean Owen Date: Wed, 30 Apr 2014 15:12:13 +0100 Subject: [PATCH] Refactor common code from across Android apps into module --- android-core/pom.xml | 40 ++ .../camera/CameraConfigurationUtils.java | 383 ++++++++++++++++++ android/pom.xml | 5 + .../camera/CameraConfigurationManager.java | 252 +----------- .../camera/metering/MeteringInterface.java | 72 ---- glass/pom.xml | 5 + .../glass/CameraConfigurationManager.java | 93 +---- pom.xml | 1 + 8 files changed, 455 insertions(+), 396 deletions(-) create mode 100644 android-core/pom.xml create mode 100644 android-core/src/main/java/com/google/zxing/client/android/camera/CameraConfigurationUtils.java delete mode 100644 android/src/com/google/zxing/client/android/camera/metering/MeteringInterface.java diff --git a/android-core/pom.xml b/android-core/pom.xml new file mode 100644 index 000000000..4776d540c --- /dev/null +++ b/android-core/pom.xml @@ -0,0 +1,40 @@ + + + + 4.0.0 + + android-core + 3.0.2-SNAPSHOT + jar + + + + com.google.android + android + + + + + com.google.zxing + zxing-parent + 3.0.2-SNAPSHOT + + + ZXing Android Core + Code common to Android applications + + diff --git a/android-core/src/main/java/com/google/zxing/client/android/camera/CameraConfigurationUtils.java b/android-core/src/main/java/com/google/zxing/client/android/camera/CameraConfigurationUtils.java new file mode 100644 index 000000000..4fd44f6cf --- /dev/null +++ b/android-core/src/main/java/com/google/zxing/client/android/camera/CameraConfigurationUtils.java @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2014 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.graphics.Point; +import android.graphics.Rect; +import android.hardware.Camera; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +/** + * Utility methods for configuring the Android camera. + * + * @author Sean Owen + */ +public final class CameraConfigurationUtils { + + private static final String TAG = "CameraConfiguration"; + + private static final int MIN_PREVIEW_PIXELS = 480 * 320; // normal screen + private static final float MAX_EXPOSURE_COMPENSATION = 1.5f; + private static final float MIN_EXPOSURE_COMPENSATION = 0.0f; + private static final double MAX_ASPECT_DISTORTION = 0.15; + private static final int MIN_FPS = 10; + private static final int AREA_PER_1000 = 400; + + private CameraConfigurationUtils() { + } + + public static void setFocus(Camera.Parameters parameters, + boolean autoFocus, + boolean disableContinuous, + boolean safeMode) { + List supportedFocusModes = parameters.getSupportedFocusModes(); + String focusMode = null; + if (autoFocus) { + if (safeMode || disableContinuous) { + focusMode = CameraConfigurationUtils.findSettableValue("focus mode", + supportedFocusModes, + Camera.Parameters.FOCUS_MODE_AUTO); + } else { + focusMode = CameraConfigurationUtils.findSettableValue("focus mode", + supportedFocusModes, + Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE, + Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO, + Camera.Parameters.FOCUS_MODE_AUTO); + } + } + // Maybe selected auto-focus but not available, so fall through here: + if (!safeMode && focusMode == null) { + focusMode = CameraConfigurationUtils.findSettableValue("focus mode", + supportedFocusModes, + Camera.Parameters.FOCUS_MODE_MACRO, + Camera.Parameters.FOCUS_MODE_EDOF); + } + if (focusMode != null) { + if (focusMode.equals(parameters.getFocusMode())) { + Log.i(TAG, "Focus mode already set to " + focusMode); + } else { + parameters.setFocusMode(focusMode); + } + } + } + + public static void setTorch(Camera.Parameters parameters, boolean on) { + List supportedFlashModes = parameters.getSupportedFlashModes(); + String flashMode; + if (on) { + flashMode = CameraConfigurationUtils.findSettableValue("flash mode", + supportedFlashModes, + Camera.Parameters.FLASH_MODE_TORCH, + Camera.Parameters.FLASH_MODE_ON); + } else { + flashMode = CameraConfigurationUtils.findSettableValue("flash mode", + supportedFlashModes, + Camera.Parameters.FLASH_MODE_OFF); + } + if (flashMode != null) { + if (flashMode.equals(parameters.getFlashMode())) { + Log.i(TAG, "Flash mode already set to " + flashMode); + } else { + Log.i(TAG, "Setting flash mode to " + flashMode); + parameters.setFlashMode(flashMode); + } + } + } + + public static void setBestExposure(Camera.Parameters parameters, boolean lightOn) { + int minExposure = parameters.getMinExposureCompensation(); + int maxExposure = parameters.getMaxExposureCompensation(); + float step = parameters.getExposureCompensationStep(); + if ((minExposure != 0 || maxExposure != 0) && step > 0.0f) { + // Set low when light is on + float targetCompensation = lightOn ? MIN_EXPOSURE_COMPENSATION : MAX_EXPOSURE_COMPENSATION; + int compensationSteps = Math.round(targetCompensation / step); + float actualCompensation = step * compensationSteps; + // Clamp value: + compensationSteps = Math.max(Math.min(compensationSteps, maxExposure), minExposure); + if (parameters.getExposureCompensation() == compensationSteps) { + Log.i(TAG, "Exposure compensation already set to " + compensationSteps + " / " + actualCompensation); + } else { + Log.i(TAG, "Setting exposure compensation to " + compensationSteps + " / " + actualCompensation); + parameters.setExposureCompensation(compensationSteps); + } + } else { + Log.i(TAG, "Camera does not support exposure compensation"); + } + } + + public static void setBestPreviewFPS(Camera.Parameters parameters) { + setBestPreviewFPS(parameters, MIN_FPS); + } + + public static void setBestPreviewFPS(Camera.Parameters parameters, int minFPS) { + List supportedPreviewFpsRanges = parameters.getSupportedPreviewFpsRange(); + Log.i(TAG, "Supported FPS ranges: " + toString(supportedPreviewFpsRanges)); + if (supportedPreviewFpsRanges != null && !supportedPreviewFpsRanges.isEmpty()) { + int[] minimumSuitableFpsRange = null; + for (int[] fpsRange : supportedPreviewFpsRanges) { + int fpsMax = fpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]; + if (fpsMax >= minFPS * 1000 && + (minimumSuitableFpsRange == null || + fpsMax > minimumSuitableFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX])) { + minimumSuitableFpsRange = fpsRange; + } + } + if (minimumSuitableFpsRange == null) { + Log.i(TAG, "No suitable FPS range?"); + } else { + int[] currentFpsRange = new int[2]; + parameters.getPreviewFpsRange(currentFpsRange); + if (Arrays.equals(currentFpsRange, minimumSuitableFpsRange)) { + Log.i(TAG, "FPS range already set to " + Arrays.toString(minimumSuitableFpsRange)); + } else { + Log.i(TAG, "Setting FPS range to " + Arrays.toString(minimumSuitableFpsRange)); + parameters.setPreviewFpsRange(minimumSuitableFpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], + minimumSuitableFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); + } + } + } + } + + public static void setFocusArea(Camera.Parameters parameters) { + if (parameters.getMaxNumFocusAreas() > 0) { + Log.i(TAG, "Old focus areas: " + toString(parameters.getFocusAreas())); + List middleArea = buildMiddleArea(AREA_PER_1000); + Log.i(TAG, "Setting focus area to : " + toString(middleArea)); + parameters.setFocusAreas(middleArea); + } else { + Log.i(TAG, "Device does not support focus areas"); + } + } + + public static void setMetering(Camera.Parameters parameters) { + if (parameters.getMaxNumMeteringAreas() > 0) { + Log.i(TAG, "Old metering areas: " + parameters.getMeteringAreas()); + List middleArea = buildMiddleArea(AREA_PER_1000); + Log.i(TAG, "Setting metering area to : " + toString(middleArea)); + parameters.setMeteringAreas(middleArea); + } else { + Log.i(TAG, "Device does not support metering areas"); + } + } + + private static List buildMiddleArea(int areaPer1000) { + return Collections.singletonList( + new Camera.Area(new Rect(-areaPer1000, -areaPer1000, areaPer1000, areaPer1000), 1)); + } + + public static void setVideoStabilization(Camera.Parameters parameters) { + if (parameters.isVideoStabilizationSupported()) { + if (parameters.getVideoStabilization()) { + Log.i(TAG, "Video stabilization already enabled"); + } else { + Log.i(TAG, "Enabling video stabilization..."); + parameters.setVideoStabilization(true); + } + } else { + Log.i(TAG, "This device does not support video stabilization"); + } + } + + public static void setBarcodeSceneMode(Camera.Parameters parameters) { + if (Camera.Parameters.SCENE_MODE_BARCODE.equals(parameters.getSceneMode())) { + Log.i(TAG, "Barcode scene mode already set"); + return; + } + String sceneMode = findSettableValue("scene mode", + parameters.getSupportedSceneModes(), + Camera.Parameters.SCENE_MODE_BARCODE); + if (sceneMode != null) { + parameters.setSceneMode(sceneMode); + } + } + + public static void setMaxZoom(Camera.Parameters parameters) { + int maxZoom = parameters.getMaxZoom(); + Log.i(TAG, "Setting zoom to max of " + maxZoom); + setZoom(parameters, maxZoom); + } + + public static void setZoom(Camera.Parameters parameters, int zoom) { + if (parameters.isZoomSupported()) { + if (parameters.getZoom() == zoom) { + Log.i(TAG, "Zoom is already set to " + zoom); + } else { + Log.i(TAG, "Setting zoom to " + zoom); + parameters.setZoom(zoom); + } + } else { + Log.i(TAG, "Zoom is not supported"); + } + } + + public static void setInvertColor(Camera.Parameters parameters) { + if (Camera.Parameters.EFFECT_NEGATIVE.equals(parameters.getColorEffect())) { + Log.i(TAG, "Negative effect already set"); + return; + } + String colorMode = + CameraConfigurationUtils.findSettableValue("color effect", + parameters.getSupportedColorEffects(), + Camera.Parameters.EFFECT_NEGATIVE); + if (colorMode != null) { + parameters.setColorEffect(colorMode); + } + } + + public static Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) { + + List rawSupportedSizes = parameters.getSupportedPreviewSizes(); + if (rawSupportedSizes == null) { + Log.w(TAG, "Device returned no supported preview sizes; using default"); + Camera.Size defaultSize = parameters.getPreviewSize(); + if (defaultSize == null) { + throw new IllegalStateException("Parameters contained no preview size!"); + } + return new Point(defaultSize.width, defaultSize.height); + } + + // Sort by size, descending + List supportedPreviewSizes = new ArrayList<>(rawSupportedSizes); + Collections.sort(supportedPreviewSizes, new Comparator() { + @Override + public int compare(Camera.Size a, Camera.Size b) { + int aPixels = a.height * a.width; + int bPixels = b.height * b.width; + if (bPixels < aPixels) { + return -1; + } + if (bPixels > aPixels) { + return 1; + } + return 0; + } + }); + + if (Log.isLoggable(TAG, Log.INFO)) { + StringBuilder previewSizesString = new StringBuilder(); + for (Camera.Size supportedPreviewSize : supportedPreviewSizes) { + previewSizesString.append(supportedPreviewSize.width).append('x') + .append(supportedPreviewSize.height).append(' '); + } + Log.i(TAG, "Supported preview sizes: " + previewSizesString); + } + + double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y; + + // Remove sizes that are unsuitable + Iterator it = supportedPreviewSizes.iterator(); + while (it.hasNext()) { + Camera.Size supportedPreviewSize = it.next(); + int realWidth = supportedPreviewSize.width; + int realHeight = supportedPreviewSize.height; + if (realWidth * realHeight < MIN_PREVIEW_PIXELS) { + it.remove(); + continue; + } + + boolean isCandidatePortrait = realWidth < realHeight; + int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth; + int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight; + double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight; + double distortion = Math.abs(aspectRatio - screenAspectRatio); + if (distortion > MAX_ASPECT_DISTORTION) { + it.remove(); + continue; + } + + if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) { + Point exactPoint = new Point(realWidth, realHeight); + Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint); + return exactPoint; + } + } + + // If no exact match, use largest preview size. This was not a great idea on older devices because + // of the additional computation needed. We're likely to get here on newer Android 4+ devices, where + // the CPU is much more powerful. + if (!supportedPreviewSizes.isEmpty()) { + Camera.Size largestPreview = supportedPreviewSizes.get(0); + Point largestSize = new Point(largestPreview.width, largestPreview.height); + Log.i(TAG, "Using largest suitable preview size: " + largestSize); + return largestSize; + } + + // If there is nothing at all suitable, return current preview size + Camera.Size defaultPreview = parameters.getPreviewSize(); + if (defaultPreview == null) { + throw new IllegalStateException("Parameters contained no preview size!"); + } + Point defaultSize = new Point(defaultPreview.width, defaultPreview.height); + Log.i(TAG, "No suitable preview sizes, using default: " + defaultSize); + return defaultSize; + } + + private static String findSettableValue(String name, + Collection supportedValues, + String... desiredValues) { + Log.i(TAG, "Requesting " + name + " value from among: " + Arrays.toString(desiredValues)); + Log.i(TAG, "Supported " + name + " values: " + supportedValues); + if (supportedValues != null) { + for (String desiredValue : desiredValues) { + if (supportedValues.contains(desiredValue)) { + Log.i(TAG, "Can set " + name + " to: " + desiredValue); + return desiredValue; + } + } + } + Log.i(TAG, "No supported values match"); + return null; + } + + private static String toString(Collection arrays) { + if (arrays == null || arrays.isEmpty()) { + return "[]"; + } + StringBuilder buffer = new StringBuilder(); + buffer.append('['); + Iterator it = arrays.iterator(); + while (it.hasNext()) { + buffer.append(Arrays.toString(it.next())); + if (it.hasNext()) { + buffer.append(", "); + } + } + buffer.append(']'); + return buffer.toString(); + } + + private static String toString(Iterable areas) { + if (areas == null) { + return null; + } + StringBuilder result = new StringBuilder(); + for (Camera.Area area : areas) { + result.append(area.rect).append(':').append(area.weight).append(' '); + } + return result.toString(); + } + +} diff --git a/android/pom.xml b/android/pom.xml index 51b019777..3b3a338ef 100644 --- a/android/pom.xml +++ b/android/pom.xml @@ -27,6 +27,11 @@ core ${project.parent.version} + + com.google.zxing + android-core + ${project.parent.version} + com.google.android android 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 c3bb3c4d3..24bd4e8fa 100644 --- a/android/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java +++ b/android/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java @@ -26,15 +26,6 @@ import android.view.Display; import android.view.WindowManager; import com.google.zxing.client.android.PreferencesActivity; -import com.google.zxing.client.android.camera.metering.MeteringInterface; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; /** * A class which deals with reading, parsing, and setting the camera parameters which are used to @@ -44,15 +35,6 @@ final class CameraConfigurationManager { private static final String TAG = "CameraConfiguration"; - // This is bigger than the size of a small screen, which is still supported. The routine - // below will still select the default (presumably 320x240) size for these. This prevents - // accidental selection of very low resolution on some devices. - private static final int MIN_PREVIEW_PIXELS = 480 * 320; // normal screen - private static final float MAX_EXPOSURE_COMPENSATION = 1.5f; - private static final float MIN_EXPOSURE_COMPENSATION = 0.0f; - private static final double MAX_ASPECT_DISTORTION = 0.15; - private static final int MIN_FPS = 5; - private final Context context; private Point screenResolution; private Point cameraResolution; @@ -72,7 +54,7 @@ final class CameraConfigurationManager { display.getSize(theScreenResolution); screenResolution = theScreenResolution; Log.i(TAG, "Screen resolution: " + screenResolution); - cameraResolution = findBestPreviewSizeValue(parameters, screenResolution); + cameraResolution = CameraConfigurationUtils.findBestPreviewSizeValue(parameters, screenResolution); Log.i(TAG, "Camera resolution: " + cameraResolution); } @@ -94,57 +76,27 @@ final class CameraConfigurationManager { initializeTorch(parameters, prefs, safeMode); - setBestPreviewFPS(parameters); + CameraConfigurationUtils.setBestPreviewFPS(parameters); - String focusMode = null; - if (prefs.getBoolean(PreferencesActivity.KEY_AUTO_FOCUS, true)) { - if (safeMode || prefs.getBoolean(PreferencesActivity.KEY_DISABLE_CONTINUOUS_FOCUS, true)) { - focusMode = findSettableValue(parameters.getSupportedFocusModes(), - Camera.Parameters.FOCUS_MODE_AUTO); - } else { - focusMode = findSettableValue(parameters.getSupportedFocusModes(), - Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE, - Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO, - Camera.Parameters.FOCUS_MODE_AUTO); - } - } - // Maybe selected auto-focus but not available, so fall through here: - if (!safeMode && focusMode == null) { - focusMode = findSettableValue(parameters.getSupportedFocusModes(), - Camera.Parameters.FOCUS_MODE_MACRO, - Camera.Parameters.FOCUS_MODE_EDOF); - } - if (focusMode != null) { - parameters.setFocusMode(focusMode); - } + CameraConfigurationUtils.setFocus( + parameters, + prefs.getBoolean(PreferencesActivity.KEY_AUTO_FOCUS, true), + prefs.getBoolean(PreferencesActivity.KEY_DISABLE_CONTINUOUS_FOCUS, true), + safeMode); if (!safeMode) { if (prefs.getBoolean(PreferencesActivity.KEY_INVERT_SCAN, false)) { - String colorMode = findSettableValue(parameters.getSupportedColorEffects(), - Camera.Parameters.EFFECT_NEGATIVE); - if (colorMode != null) { - parameters.setColorEffect(colorMode); - } + CameraConfigurationUtils.setInvertColor(parameters); } if (!prefs.getBoolean(PreferencesActivity.KEY_DISABLE_BARCODE_SCENE_MODE, true)) { - String sceneMode = findSettableValue(parameters.getSupportedSceneModes(), - Camera.Parameters.SCENE_MODE_BARCODE); - if (sceneMode != null) { - parameters.setSceneMode(sceneMode); - } + CameraConfigurationUtils.setBarcodeSceneMode(parameters); } if (!prefs.getBoolean(PreferencesActivity.KEY_DISABLE_METERING, true)) { - if (parameters.isVideoStabilizationSupported()) { - Log.i(TAG, "Enabling video stabilization..."); - parameters.setVideoStabilization(true); - } else { - Log.i(TAG, "This device does not support video stabilization"); - } - - MeteringInterface.setFocusArea(parameters); - MeteringInterface.setMetering(parameters); + CameraConfigurationUtils.setVideoStabilization(parameters); + CameraConfigurationUtils.setFocusArea(parameters); + CameraConfigurationUtils.setMetering(parameters); } } @@ -195,185 +147,11 @@ final class CameraConfigurationManager { } private void doSetTorch(Camera.Parameters parameters, boolean newSetting, boolean safeMode) { - 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); - } - if (flashMode != null) { - parameters.setFlashMode(flashMode); - } - + CameraConfigurationUtils.setTorch(parameters, newSetting); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - if (!prefs.getBoolean(PreferencesActivity.KEY_DISABLE_EXPOSURE, true)) { - if (!safeMode) { - int minExposure = parameters.getMinExposureCompensation(); - int maxExposure = parameters.getMaxExposureCompensation(); - if (minExposure != 0 || maxExposure != 0) { - float step = parameters.getExposureCompensationStep(); - int desiredCompensation; - if (newSetting) { - // Light on; set low exposure compensation - desiredCompensation = Math.max((int) (MIN_EXPOSURE_COMPENSATION / step), minExposure); - } else { - // Light off; set high compensation - desiredCompensation = Math.min((int) (MAX_EXPOSURE_COMPENSATION / step), maxExposure); - } - Log.i(TAG, "Setting exposure compensation to " + desiredCompensation + " / " + (step * desiredCompensation)); - parameters.setExposureCompensation(desiredCompensation); - } else { - Log.i(TAG, "Camera does not support exposure compensation"); - } - } + if (!safeMode && !prefs.getBoolean(PreferencesActivity.KEY_DISABLE_EXPOSURE, true)) { + CameraConfigurationUtils.setBestExposure(parameters, newSetting); } } - private static void setBestPreviewFPS(Camera.Parameters parameters) { - // Required for Glass compatibility; also improves battery/CPU performance a tad - List supportedPreviewFpsRanges = parameters.getSupportedPreviewFpsRange(); - Log.i(TAG, "Supported FPS ranges: " + toString(supportedPreviewFpsRanges)); - if (supportedPreviewFpsRanges != null && !supportedPreviewFpsRanges.isEmpty()) { - int[] minimumSuitableFpsRange = null; - for (int[] fpsRange : supportedPreviewFpsRanges) { - int fpsMax = fpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]; - if (fpsMax >= MIN_FPS * 1000 && - (minimumSuitableFpsRange == null || - fpsMax > minimumSuitableFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX])) { - minimumSuitableFpsRange = fpsRange; - } - } - if (minimumSuitableFpsRange == null) { - Log.i(TAG, "No suitable FPS range?"); - } else { - int[] currentFpsRange = new int[2]; - parameters.getPreviewFpsRange(currentFpsRange); - if (!Arrays.equals(currentFpsRange, minimumSuitableFpsRange)) { - Log.i(TAG, "Setting FPS range to " + Arrays.toString(minimumSuitableFpsRange)); - parameters.setPreviewFpsRange(minimumSuitableFpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], - minimumSuitableFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); - } - } - } - } - - // Actually prints the arrays properly: - private static String toString(Collection arrays) { - if (arrays == null || arrays.isEmpty()) { - return "[]"; - } - StringBuilder buffer = new StringBuilder(); - buffer.append('['); - Iterator it = arrays.iterator(); - while (it.hasNext()) { - buffer.append(Arrays.toString(it.next())); - if (it.hasNext()) { - buffer.append(", "); - } - } - buffer.append(']'); - return buffer.toString(); - } - - private Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) { - - List rawSupportedSizes = parameters.getSupportedPreviewSizes(); - if (rawSupportedSizes == null) { - Log.w(TAG, "Device returned no supported preview sizes; using default"); - Camera.Size defaultSize = parameters.getPreviewSize(); - return new Point(defaultSize.width, defaultSize.height); - } - - // Sort by size, descending - List supportedPreviewSizes = new ArrayList<>(rawSupportedSizes); - Collections.sort(supportedPreviewSizes, new Comparator() { - @Override - public int compare(Camera.Size a, Camera.Size b) { - int aPixels = a.height * a.width; - int bPixels = b.height * b.width; - if (bPixels < aPixels) { - return -1; - } - if (bPixels > aPixels) { - return 1; - } - return 0; - } - }); - - if (Log.isLoggable(TAG, Log.INFO)) { - StringBuilder previewSizesString = new StringBuilder(); - for (Camera.Size supportedPreviewSize : supportedPreviewSizes) { - previewSizesString.append(supportedPreviewSize.width).append('x') - .append(supportedPreviewSize.height).append(' '); - } - Log.i(TAG, "Supported preview sizes: " + previewSizesString); - } - - double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y; - - // Remove sizes that are unsuitable - Iterator it = supportedPreviewSizes.iterator(); - while (it.hasNext()) { - Camera.Size supportedPreviewSize = it.next(); - int realWidth = supportedPreviewSize.width; - int realHeight = supportedPreviewSize.height; - if (realWidth * realHeight < MIN_PREVIEW_PIXELS) { - it.remove(); - continue; - } - - boolean isCandidatePortrait = realWidth < realHeight; - int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth; - int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight; - double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight; - double distortion = Math.abs(aspectRatio - screenAspectRatio); - if (distortion > MAX_ASPECT_DISTORTION) { - it.remove(); - continue; - } - - if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) { - Point exactPoint = new Point(realWidth, realHeight); - Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint); - return exactPoint; - } - } - - // If no exact match, use largest preview size. This was not a great idea on older devices because - // of the additional computation needed. We're likely to get here on newer Android 4+ devices, where - // the CPU is much more powerful. - if (!supportedPreviewSizes.isEmpty()) { - Camera.Size largestPreview = supportedPreviewSizes.get(0); - Point largestSize = new Point(largestPreview.width, largestPreview.height); - Log.i(TAG, "Using largest suitable preview size: " + largestSize); - return largestSize; - } - - // If there is nothing at all suitable, return current preview size - Camera.Size defaultPreview = parameters.getPreviewSize(); - Point defaultSize = new Point(defaultPreview.width, defaultPreview.height); - Log.i(TAG, "No suitable preview sizes, using default: " + defaultSize); - return defaultSize; - } - - 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; - } - } - } - Log.i(TAG, "Settable value: " + result); - return result; - } - } diff --git a/android/src/com/google/zxing/client/android/camera/metering/MeteringInterface.java b/android/src/com/google/zxing/client/android/camera/metering/MeteringInterface.java deleted file mode 100644 index aad310850..000000000 --- a/android/src/com/google/zxing/client/android/camera/metering/MeteringInterface.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2014 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.metering; - -import java.util.Collections; -import java.util.List; - -import android.graphics.Rect; -import android.hardware.Camera; -import android.util.Log; - -public final class MeteringInterface { - - private static final String TAG = MeteringInterface.class.getSimpleName(); - private static final int AREA_PER_1000 = 400; - - private MeteringInterface() { - } - - public static void setFocusArea(Camera.Parameters parameters) { - if (parameters.getMaxNumFocusAreas() > 0) { - Log.i(TAG, "Old focus areas: " + toString(parameters.getFocusAreas())); - List middleArea = buildMiddleArea(); - Log.i(TAG, "Setting focus area to : " + toString(middleArea)); - parameters.setFocusAreas(middleArea); - } else { - Log.i(TAG, "Device does not support focus areas"); - } - } - - public static void setMetering(Camera.Parameters parameters) { - if (parameters.getMaxNumMeteringAreas() > 0) { - Log.i(TAG, "Old metering areas: " + parameters.getMeteringAreas()); - List middleArea = buildMiddleArea(); - Log.i(TAG, "Setting metering area to : " + toString(middleArea)); - parameters.setMeteringAreas(middleArea); - } else { - Log.i(TAG, "Device does not support metering areas"); - } - } - - private static List buildMiddleArea() { - return Collections.singletonList( - new Camera.Area(new Rect(-AREA_PER_1000, -AREA_PER_1000, AREA_PER_1000, AREA_PER_1000), 1)); - } - - private static String toString(Iterable areas) { - if (areas == null) { - return null; - } - StringBuilder result = new StringBuilder(); - for (Camera.Area area : areas) { - result.append(area.rect).append(':').append(area.weight).append(' '); - } - return result.toString(); - } - -} diff --git a/glass/pom.xml b/glass/pom.xml index a33e70258..930b383b1 100644 --- a/glass/pom.xml +++ b/glass/pom.xml @@ -27,6 +27,11 @@ core ${project.parent.version} + + com.google.zxing + android-core + ${project.parent.version} + com.google.android android diff --git a/glass/src/com/google/zxing/client/glass/CameraConfigurationManager.java b/glass/src/com/google/zxing/client/glass/CameraConfigurationManager.java index d343946c0..4af3b4dbf 100644 --- a/glass/src/com/google/zxing/client/glass/CameraConfigurationManager.java +++ b/glass/src/com/google/zxing/client/glass/CameraConfigurationManager.java @@ -16,24 +16,15 @@ package com.google.zxing.client.glass; -import android.graphics.Rect; import android.hardware.Camera; -import android.util.Log; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import com.google.zxing.client.android.camera.CameraConfigurationUtils; /** * @author Sean Owen */ final class CameraConfigurationManager { - private static final String TAG = "CameraConfiguration"; - private static final int AREA_PER_1000 = 400; - private static final int MIN_FPS = 10; - private CameraConfigurationManager() { } @@ -46,83 +37,11 @@ final class CameraConfigurationManager { } private static void configureAdvanced(Camera.Parameters parameters) { - - setBestPreviewFPS(parameters); - - String sceneMode = findSettableValue(parameters.getSupportedSceneModes(), - Camera.Parameters.SCENE_MODE_BARCODE); - if (sceneMode != null) { - parameters.setSceneMode(sceneMode); - } else { - Log.i(TAG, "Scene mode is not supported"); - } - - if (parameters.isVideoStabilizationSupported()) { - Log.i(TAG, "Enabling video stabilization..."); - parameters.setVideoStabilization(true); - } else { - Log.i(TAG, "This device does not support video stabilization"); - } - - if (parameters.getMaxNumMeteringAreas() > 0) { - Log.i(TAG, "Old metering areas: " + parameters.getMeteringAreas()); - List middleArea = Collections.singletonList( - new Camera.Area(new Rect(-AREA_PER_1000, -AREA_PER_1000, AREA_PER_1000, AREA_PER_1000), 1)); - parameters.setMeteringAreas(middleArea); - } else { - Log.i(TAG, "Device does not support metering areas"); - } - - if (parameters.isZoomSupported()) { - Log.i(TAG, "Setting to max zoom"); - parameters.setZoom(parameters.getMaxZoom()); - } else { - Log.i(TAG, "Zoom is not supported"); - } - - } - - 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; - } - } - } - Log.i(TAG, "Settable value: " + result); - return result; - } - - private static void setBestPreviewFPS(Camera.Parameters parameters) { - // Required for Glass compatibility; also improves battery/CPU performance a tad - List supportedPreviewFpsRanges = parameters.getSupportedPreviewFpsRange(); - if (supportedPreviewFpsRanges != null && !supportedPreviewFpsRanges.isEmpty()) { - int[] minimumSuitableFpsRange = null; - for (int[] fpsRange : supportedPreviewFpsRanges) { - int fpsMax = fpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]; - if (fpsMax >= MIN_FPS * 1000 && - (minimumSuitableFpsRange == null || - fpsMax > minimumSuitableFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX])) { - minimumSuitableFpsRange = fpsRange; - } - } - if (minimumSuitableFpsRange == null) { - Log.i(TAG, "No suitable FPS range?"); - } else { - int[] currentFpsRange = new int[2]; - parameters.getPreviewFpsRange(currentFpsRange); - if (!Arrays.equals(currentFpsRange, minimumSuitableFpsRange)) { - Log.i(TAG, "Setting FPS range to " + Arrays.toString(minimumSuitableFpsRange)); - parameters.setPreviewFpsRange(minimumSuitableFpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], - minimumSuitableFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); - } - } - } + CameraConfigurationUtils.setBestPreviewFPS(parameters); + CameraConfigurationUtils.setBarcodeSceneMode(parameters); + CameraConfigurationUtils.setVideoStabilization(parameters); + CameraConfigurationUtils.setMetering(parameters); + CameraConfigurationUtils.setMaxZoom(parameters); } } diff --git a/pom.xml b/pom.xml index 6d8bbd065..c53207ce1 100644 --- a/pom.xml +++ b/pom.xml @@ -507,6 +507,7 @@ + android-core android androidtest glass