最近公司项目App中要集成二维码扫描来适应在户外工作的时候,对码头集装箱等上面贴的A4纸张打印的二维码进行识别, 一般App二维码集成后,能扫出来就不管了,但是我们在集成成功后,根据用户反馈,在户外的环境下,很多二维码识别不了,或者识别速度慢,我们自己也是适用了一下,发现也确实是这样.

一般造成这个识别不出来的原因,我们总结了以下几点:

  1. A4纸张打印的标签二维码, 本来打印就不是特别清晰,有些像素点,不一定都打印了出来,
  2. 户外环境,多变,灰尘,粉尘影响
  3. 日晒雨淋,还有各种划痕,造成了二维码破损和有污渍
  4. Android手机配置不一样,有的手机好一点,像素高,有的用户的像素低

大概就是这些,但是用基于QBar(在Zxing上做了优化)的微信,却能很快的识别出上面几种情况造成的二维码; 基于libqrencode 库集成的支付宝或者钉钉二维码扫描,一样也能识别出来;还有IOS也就是调用系统的扫描,也一样能够扫描出来,为啥我们大android不行?

老板不管这些,只是说了,别人的可以,为啥你的不可以,那就是你的问题.......

网上找了很多各种几千个赞的第三方集成的二维码,根本就不能满足上面的需求,当时感觉真心不知道怎么办好了.

唯独网上找的这个还可以一点:https://github.com/vondear/RxTool 但是破损一些的还是扫描不出来;那个网上几千个赞的一片枫叶的 ,这种环境下的二维码扫描根本边都摸不到.

还有郭林推荐的:https://github.com/al4fun/SimpleScanner 这个库,虽然是大神推荐的,但是比上面的这个,还要差那么好几点,郭林的推荐的二维码扫描链接:https://mp.weixin.qq.com/s/aPqSK1FlsPiENzSE48BVUA

没办法,最后只能自己动手,网上找的,没有找到合适的,目前我们修改的二维码扫描基本可以做到:除了破损的识别不了,其他的都能识别,就是有时候速度慢了点,要多对一下焦,勉强能够比上面好那么一点点而已.

代码如下: (这里面很多类都在原有类的基础上有改动,虽然类名相同,但是里面的方法有些有变动!)

build.gradle

dependencies{api fileTree(include: ['*.jar'], dir: 'libs')api files('libs/core-3.3.0.jar')//    provided 'com.android.support:appcompat-v7:26.1.0'compileOnly 'com.android.support:design:26.1.0'compileOnly 'com.android.support:support-vector-drawable:26.1.0'
}

文件目录如下:

ZxingConfig.java
public class ZxingConfig implements Serializable {/*是否播放声音*/private boolean isPlayBeep = true;/*是否震动*/private boolean isShake = false;/*是否显示下方的其他功能布局*/private boolean isShowbottomLayout = true;/*是否显示闪光灯按钮*/private boolean isShowFlashLight = true;/*是否显示相册按钮*/private boolean isShowAlbum = true;public boolean isPlayBeep() {return isPlayBeep;}public void setPlayBeep(boolean playBeep) {isPlayBeep = playBeep;}public boolean isShake() {return isShake;}public void setShake(boolean shake) {isShake = shake;}public boolean isShowbottomLayout() {return isShowbottomLayout;}public void setShowbottomLayout(boolean showbottomLayout) {isShowbottomLayout = showbottomLayout;}public boolean isShowFlashLight() {return isShowFlashLight;}public void setShowFlashLight(boolean showFlashLight) {isShowFlashLight = showFlashLight;}public boolean isShowAlbum() {return isShowAlbum;}public void setShowAlbum(boolean showAlbum) {isShowAlbum = showAlbum;}
}
CameraFacing.java
public enum CameraFacing {BACK,  // must be value 0!FRONT, // must be value 1!}
OpenCamera.java
public final class OpenCamera {private final int          index;private final Camera       camera;private final CameraFacing facing;private final int          orientation;public OpenCamera(int index, Camera camera, CameraFacing facing, int orientation) {this.index = index;this.camera = camera;this.facing = facing;this.orientation = orientation;}public Camera getCamera() {return camera;}public CameraFacing getFacing() {return facing;}public int getOrientation() {return orientation;}@Overridepublic String toString() {return "Camera #" + index + " : " + facing + ',' + orientation;}}
OpenCameraInterface.java
public final class OpenCameraInterface {private static final String TAG = OpenCameraInterface.class.getName();private OpenCameraInterface() {}/*** For {@link #open(int)}, means no preference for which camera to open.*/public static final int NO_REQUESTED_CAMERA = -1;/*** Opens the requested camera with {@link Camera#open(int)}, if one exists.** @param cameraId camera ID of the camera to use. A negative value*                 or {@link #NO_REQUESTED_CAMERA} means "no preference", in which case a rear-facing*                 camera is returned if possible or else any camera* @return handle to {@link OpenCamera} that was opened*/public static OpenCamera open(int cameraId) {int numCameras = Camera.getNumberOfCameras();if (numCameras == 0) {Log.w(TAG, "No cameras!");return null;}boolean explicitRequest = cameraId >= 0;Camera.CameraInfo selectedCameraInfo = null;int index;if (explicitRequest) {index = cameraId;selectedCameraInfo = new Camera.CameraInfo();Camera.getCameraInfo(index, selectedCameraInfo);} else {index = 0;while (index < numCameras) {Camera.CameraInfo cameraInfo = new Camera.CameraInfo();Camera.getCameraInfo(index, cameraInfo);CameraFacing reportedFacing = CameraFacing.values()[cameraInfo.facing];if (reportedFacing == CameraFacing.BACK) {selectedCameraInfo = cameraInfo;break;}index++;}}Camera camera;if (index < numCameras) {Log.i(TAG, "Opening camera #" + index);camera = Camera.open(index);} else {if (explicitRequest) {Log.w(TAG, "Requested camera does not exist: " + cameraId);camera = null;} else {Log.i(TAG, "No camera facing " + CameraFacing.BACK + "; returning camera #0");camera = Camera.open(0);selectedCameraInfo = new Camera.CameraInfo();Camera.getCameraInfo(0, selectedCameraInfo);}}if (camera == null) {return null;}return new OpenCamera(index,camera,CameraFacing.values()[selectedCameraInfo.facing],selectedCameraInfo.orientation);}}
AutoFocusManager.java
final class AutoFocusManager implements Camera.AutoFocusCallback {private static final String TAG = AutoFocusManager.class.getSimpleName();private static final long AUTO_FOCUS_INTERVAL_MS = 2000L;private static final Collection<String> FOCUS_MODES_CALLING_AF;static {FOCUS_MODES_CALLING_AF = new ArrayList<>(2);FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO);FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO);}private boolean stopped;private boolean focusing;private final boolean useAutoFocus;private final Camera camera;private AsyncTask<?,?,?> outstandingTask;AutoFocusManager(Context context, Camera camera) {this.camera = camera;SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);String currentFocusMode = camera.getParameters().getFocusMode();useAutoFocus =sharedPrefs.getBoolean(QRConstants.KEY_AUTO_FOCUS, true) &&FOCUS_MODES_CALLING_AF.contains(currentFocusMode);Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus);start();}@Overridepublic synchronized void onAutoFocus(boolean success, Camera theCamera) {focusing = false;autoFocusAgainLater();}private synchronized void autoFocusAgainLater() {if (!stopped && outstandingTask == null) {AutoFocusTask newTask = new AutoFocusTask();try {newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);outstandingTask = newTask;} catch (RejectedExecutionException ree) {Log.w(TAG, "Could not request auto focus", ree);}}}synchronized void start() {
//    if (useAutoFocus) {outstandingTask = null;if (!stopped && !focusing) {try {camera.autoFocus(this);focusing = true;} catch (RuntimeException re) {// Have heard RuntimeException reported in Android 4.0.x+; continue?Log.w(TAG, "Unexpected exception while focusing", re);// Try again later to keep cycle goingautoFocusAgainLater();}}
//    }}private synchronized void cancelOutstandingTask() {if (outstandingTask != null) {if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) {outstandingTask.cancel(true);}outstandingTask = null;}}synchronized void stop() {stopped = true;
//    if (useAutoFocus) {cancelOutstandingTask();// Doesn't hurt to call this even if not focusingtry {camera.cancelAutoFocus();} catch (RuntimeException re) {// Have heard RuntimeException reported in Android 4.0.x+; continue?Log.w(TAG, "Unexpected exception while cancelling focusing", re);}
//    }}private final class AutoFocusTask extends AsyncTask<Object,Object,Object> {@Overrideprotected Object doInBackground(Object... voids) {try {Thread.sleep(AUTO_FOCUS_INTERVAL_MS);} catch (InterruptedException e) {// continue}start();return null;}}}
CameraConfigurationManager.java
final class CameraConfigurationManager {private static final String TAG = "CameraConfiguration";private final Context context;private int cwNeededRotation;private int cwRotationFromDisplayToCamera;private Point screenResolution;private Point cameraResolution;private Point bestPreviewSize;private Point previewSizeOnScreen;CameraConfigurationManager(Context context) {this.context = context;}/*** Reads, one time, values from the camera that are needed by the app.*/void initFromCameraParameters(OpenCamera camera) {Camera.Parameters parameters = camera.getCamera().getParameters();WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);Display display = manager.getDefaultDisplay();int displayRotation = display.getRotation();int cwRotationFromNaturalToDisplay;switch (displayRotation) {case Surface.ROTATION_0:cwRotationFromNaturalToDisplay = 0;break;case Surface.ROTATION_90:cwRotationFromNaturalToDisplay = 90;break;case Surface.ROTATION_180:cwRotationFromNaturalToDisplay = 180;break;case Surface.ROTATION_270:cwRotationFromNaturalToDisplay = 270;break;default:// Have seen this return incorrect values like -90if (displayRotation % 90 == 0) {cwRotationFromNaturalToDisplay = (360 + displayRotation) % 360;} else {throw new IllegalArgumentException("Bad rotation: " + displayRotation);}}Log.i(TAG, "Display at: " + cwRotationFromNaturalToDisplay);int cwRotationFromNaturalToCamera = camera.getOrientation();Log.i(TAG, "Camera at: " + cwRotationFromNaturalToCamera);// Still not 100% sure about this. But acts like we need to flip this:if (camera.getFacing() == CameraFacing.FRONT) {cwRotationFromNaturalToCamera = (360 - cwRotationFromNaturalToCamera) % 360;Log.i(TAG, "Front camera overriden to: " + cwRotationFromNaturalToCamera);}/*SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);String overrideRotationString;if (camera.getFacing() == CameraFacing.FRONT) {overrideRotationString = prefs.getString(PreferencesActivity.KEY_FORCE_CAMERA_ORIENTATION_FRONT, null);} else {overrideRotationString = prefs.getString(PreferencesActivity.KEY_FORCE_CAMERA_ORIENTATION, null);}if (overrideRotationString != null && !"-".equals(overrideRotationString)) {Log.i(TAG, "Overriding camera manually to " + overrideRotationString);cwRotationFromNaturalToCamera = Integer.parseInt(overrideRotationString);}*/cwRotationFromDisplayToCamera =(360 + cwRotationFromNaturalToCamera - cwRotationFromNaturalToDisplay) % 360;Log.i(TAG, "Final display orientation: " + cwRotationFromDisplayToCamera);if (camera.getFacing() == CameraFacing.FRONT) {Log.i(TAG, "Compensating rotation for front camera");cwNeededRotation = (360 - cwRotationFromDisplayToCamera) % 360;} else {cwNeededRotation = cwRotationFromDisplayToCamera;}Log.i(TAG, "Clockwise rotation from display to camera: " + cwNeededRotation);Point theScreenResolution = new Point();display.getSize(theScreenResolution);screenResolution = theScreenResolution;Log.i(TAG, "Screen resolution in current orientation: " + screenResolution);cameraResolution = CameraConfigurationUtils.findBestPreviewSizeValue(parameters, screenResolution);Log.i(TAG, "Camera resolution: " + cameraResolution);bestPreviewSize = CameraConfigurationUtils.findBestPreviewSizeValue(parameters, screenResolution);Log.i(TAG, "Best available preview size: " + bestPreviewSize);boolean isScreenPortrait = screenResolution.x < screenResolution.y;boolean isPreviewSizePortrait = bestPreviewSize.x < bestPreviewSize.y;if (isScreenPortrait == isPreviewSizePortrait) {previewSizeOnScreen = bestPreviewSize;} else {previewSizeOnScreen = new Point(bestPreviewSize.y, bestPreviewSize.x);}Log.i(TAG, "Preview size on screen: " + previewSizeOnScreen);}void setDesiredCameraParameters(OpenCamera camera, boolean safeMode) {Camera theCamera = camera.getCamera();Camera.Parameters parameters = theCamera.getParameters();if (parameters == null) {Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration.");return;}Log.i(TAG, "Initial camera parameters: " + parameters.flatten());if (safeMode) {Log.w(TAG, "In camera config safe mode -- most settings will not be honored");}//        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);initializeTorch(parameters, safeMode, QRConstants.disableExposure);CameraConfigurationUtils.setFocus(parameters,//是否支持自动对焦QRConstants.autoFocus,true,safeMode);if (!safeMode) {////CameraConfigurationUtils.setInvertColor(parameters);CameraConfigurationUtils.setBarcodeSceneMode(parameters);CameraConfigurationUtils.setVideoStabilization(parameters);CameraConfigurationUtils.setFocusArea(parameters);CameraConfigurationUtils.setMetering(parameters);}parameters.setPreviewSize(bestPreviewSize.x, bestPreviewSize.y);theCamera.setParameters(parameters);theCamera.setDisplayOrientation(cwRotationFromDisplayToCamera);Camera.Parameters afterParameters = theCamera.getParameters();Camera.Size afterSize = afterParameters.getPreviewSize();if (afterSize != null && (bestPreviewSize.x != afterSize.width || bestPreviewSize.y != afterSize.height)) {Log.w(TAG, "Camera said it supported preview size " + bestPreviewSize.x + 'x' + bestPreviewSize.y +", but after setting it, preview size is " + afterSize.width + 'x' + afterSize.height);bestPreviewSize.x = afterSize.width;bestPreviewSize.y = afterSize.height;}}Point getBestPreviewSize() {return bestPreviewSize;}Point getPreviewSizeOnScreen() {return previewSizeOnScreen;}Point getCameraResolution() {return cameraResolution;}Point getScreenResolution() {return screenResolution;}int getCWNeededRotation() {return cwNeededRotation;}boolean getTorchState(Camera camera) {if (camera != null) {Camera.Parameters parameters = camera.getParameters();if (parameters != null) {String flashMode = camera.getParameters().getFlashMode();return flashMode != null &&(Camera.Parameters.FLASH_MODE_ON.equals(flashMode) ||Camera.Parameters.FLASH_MODE_TORCH.equals(flashMode));}}return false;}void setTorch(Camera camera, boolean newSetting) {Camera.Parameters parameters = camera.getParameters();doSetTorch(parameters, newSetting, false, QRConstants.disableExposure);camera.setParameters(parameters);}private void initializeTorch(Camera.Parameters parameters, boolean safeMode, boolean disableExposure) {boolean currentSetting = QRConstants.frontLightMode == FrontLightMode.ON;doSetTorch(parameters, currentSetting, safeMode, disableExposure);}private void doSetTorch(Camera.Parameters parameters, boolean newSetting, boolean safeMode, boolean disableExposure) {CameraConfigurationUtils.setTorch(parameters, newSetting);if (!safeMode && !disableExposure) {CameraConfigurationUtils.setBestExposure(parameters, newSetting);}}}
CameraConfigurationUtils.java
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
public final class CameraConfigurationUtils {private static final String TAG = "CameraConfiguration";private static final Pattern SEMICOLON = Pattern.compile(";");private static final int MIN_PREVIEW_PIXELS = 480 * 320; // normal screenprivate 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 MAX_FPS = 20;private static final int AREA_PER_1000 = 400;private CameraConfigurationUtils() {}public static void setFocus(Camera.Parameters parameters,boolean autoFocus,boolean disableContinuous,boolean safeMode) {List<String> supportedFocusModes = parameters.getSupportedFocusModes();String focusMode = null;if (autoFocus) {if (safeMode || disableContinuous) {focusMode = findSettableValue("focus mode",supportedFocusModes,Camera.Parameters.FOCUS_MODE_AUTO);} else {focusMode = 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 = 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<String> supportedFlashModes = parameters.getSupportedFlashModes();String flashMode;if (on) {flashMode = findSettableValue("flash mode",supportedFlashModes,Camera.Parameters.FLASH_MODE_TORCH,Camera.Parameters.FLASH_MODE_ON);} else {flashMode = 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 onfloat 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, MAX_FPS);}public static void setBestPreviewFPS(Camera.Parameters parameters, int minFPS, int maxFPS) {List<int[]> supportedPreviewFpsRanges = parameters.getSupportedPreviewFpsRange();Log.i(TAG, "Supported FPS ranges: " + toString(supportedPreviewFpsRanges));if (supportedPreviewFpsRanges != null && !supportedPreviewFpsRanges.isEmpty()) {int[] suitableFPSRange = null;for (int[] fpsRange : supportedPreviewFpsRanges) {int thisMin = fpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX];int thisMax = fpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX];if (thisMin >= minFPS * 1000 && thisMax <= maxFPS * 1000) {suitableFPSRange = fpsRange;break;}}if (suitableFPSRange == null) {Log.i(TAG, "No suitable FPS range?");} else {int[] currentFpsRange = new int[2];parameters.getPreviewFpsRange(currentFpsRange);if (Arrays.equals(currentFpsRange, suitableFPSRange)) {Log.i(TAG, "FPS range already set to " + Arrays.toString(suitableFPSRange));} else {Log.i(TAG, "Setting FPS range to " + Arrays.toString(suitableFPSRange));parameters.setPreviewFpsRange(suitableFPSRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],suitableFPSRange[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<Camera.Area> 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<Camera.Area> 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<Camera.Area> 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 setZoom(Camera.Parameters parameters, double targetZoomRatio) {if (parameters.isZoomSupported()) {Integer zoom = indexOfClosestZoom(parameters, targetZoomRatio);if (zoom == null) {return;}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");}}private static Integer indexOfClosestZoom(Camera.Parameters parameters, double targetZoomRatio) {List<Integer> ratios = parameters.getZoomRatios();Log.i(TAG, "Zoom ratios: " + ratios);int maxZoom = parameters.getMaxZoom();if (ratios == null || ratios.isEmpty() || ratios.size() != maxZoom + 1) {Log.w(TAG, "Invalid zoom ratios!");return null;}double target100 = 100.0 * targetZoomRatio;double smallestDiff = Double.POSITIVE_INFINITY;int closestIndex = 0;for (int i = 0; i < ratios.size(); i++) {double diff = Math.abs(ratios.get(i) - target100);if (diff < smallestDiff) {smallestDiff = diff;closestIndex = i;}}Log.i(TAG, "Chose zoom ratio of " + (ratios.get(closestIndex) / 100.0));return closestIndex;}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 = 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<Camera.Size> 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, descendingList<Camera.Size> supportedPreviewSizes = new ArrayList<>(rawSupportedSizes);Collections.sort(supportedPreviewSizes, new Comparator<Camera.Size>() {@Overridepublic 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 unsuitableIterator<Camera.Size> 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 sizeCamera.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<String> 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<int[]> arrays) {if (arrays == null || arrays.isEmpty()) {return "[]";}StringBuilder buffer = new StringBuilder();buffer.append('[');Iterator<int[]> 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<Camera.Area> 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();}public static String collectStats(Camera.Parameters parameters) {return collectStats(parameters.flatten());}public static String collectStats(CharSequence flattenedParams) {StringBuilder result = new StringBuilder(1000);result.append("BOARD=").append(Build.BOARD).append('\n');result.append("BRAND=").append(Build.BRAND).append('\n');result.append("CPU_ABI=").append(Build.CPU_ABI).append('\n');result.append("DEVICE=").append(Build.DEVICE).append('\n');result.append("DISPLAY=").append(Build.DISPLAY).append('\n');result.append("FINGERPRINT=").append(Build.FINGERPRINT).append('\n');result.append("HOST=").append(Build.HOST).append('\n');result.append("ID=").append(Build.ID).append('\n');result.append("MANUFACTURER=").append(Build.MANUFACTURER).append('\n');result.append("MODEL=").append(Build.MODEL).append('\n');result.append("PRODUCT=").append(Build.PRODUCT).append('\n');result.append("TAGS=").append(Build.TAGS).append('\n');result.append("TIME=").append(Build.TIME).append('\n');result.append("TYPE=").append(Build.TYPE).append('\n');result.append("USER=").append(Build.USER).append('\n');result.append("VERSION.CODENAME=").append(Build.VERSION.CODENAME).append('\n');result.append("VERSION.INCREMENTAL=").append(Build.VERSION.INCREMENTAL).append('\n');result.append("VERSION.RELEASE=").append(Build.VERSION.RELEASE).append('\n');result.append("VERSION.SDK_INT=").append(Build.VERSION.SDK_INT).append('\n');if (flattenedParams != null) {String[] params = SEMICOLON.split(flattenedParams);Arrays.sort(params);for (String param : params) {result.append(param).append('\n');}}return result.toString();}}
CameraManager.java
public final class CameraManager {private static final String TAG = CameraManager.class.getSimpleName();private static final int MIN_FRAME_WIDTH = 240;private static final int MIN_FRAME_HEIGHT = 240;private static final int MAX_FRAME_WIDTH = 1200; // = 5/8 * 1920private static final int MAX_FRAME_HEIGHT = 675; // = 5/8 * 1080private final Context                    context;private final CameraConfigurationManager configManager;private       OpenCamera                 camera;private       AutoFocusManager           autoFocusManager;private       Rect                       framingRect;private       Rect                       framingRectInPreview;private       boolean                    initialized;private       boolean                    previewing;private int requestedCameraId = OpenCameraInterface.NO_REQUESTED_CAMERA;private int requestedFramingRectWidth;private int requestedFramingRectHeight;/*** Preview frames are delivered here, which we pass on to the registered handler. Make sure to* clear the handler so it will only receive one message.*/private final PreviewCallback previewCallback;public CameraManager(Context context) {this.context = context;this.configManager = new CameraConfigurationManager(context);previewCallback = new PreviewCallback(configManager);}/*** Opens the camera driver and initializes the hardware parameters.** @param holder The surface object which the camera will draw preview frames into.* @throws IOException Indicates the camera driver failed to open.*/public synchronized void openDriver(SurfaceHolder holder) throws IOException {OpenCamera theCamera = camera;if (theCamera == null) {theCamera = OpenCameraInterface.open(requestedCameraId);if (theCamera == null) {throw new IOException("Camera.open() failed to return object from driver");}camera = theCamera;}if (!initialized) {initialized = true;configManager.initFromCameraParameters(theCamera);if (requestedFramingRectWidth > 0 && requestedFramingRectHeight > 0) {setManualFramingRect(requestedFramingRectWidth, requestedFramingRectHeight);requestedFramingRectWidth = 0;requestedFramingRectHeight = 0;}}Camera cameraObject = theCamera.getCamera();Camera.Parameters parameters = cameraObject.getParameters();String parametersFlattened = parameters == null ? null : parameters.flatten(); // Save these, temporarilytry {configManager.setDesiredCameraParameters(theCamera, false);} catch (RuntimeException re) {// Driver failedLog.w(TAG, "Camera rejected parameters. Setting only minimal safe-mode parameters");Log.i(TAG, "Resetting to saved camera params: " + parametersFlattened);// Reset:if (parametersFlattened != null) {parameters = cameraObject.getParameters();parameters.unflatten(parametersFlattened);try {cameraObject.setParameters(parameters);configManager.setDesiredCameraParameters(theCamera, true);} catch (RuntimeException re2) {// Well, darn. Give upLog.w(TAG, "Camera rejected even safe-mode parameters! No configuration");}}}cameraObject.setPreviewDisplay(holder);}public synchronized boolean isOpen() {return camera != null;}/*** Closes the camera driver if still in use.*/public synchronized void closeDriver() {if (camera != null) {camera.getCamera().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;framingRectInPreview = null;}}/*** Asks the camera hardware to begin drawing preview frames to the screen.*/public synchronized void startPreview() {OpenCamera theCamera = camera;if (theCamera != null && !previewing) {theCamera.getCamera().startPreview();previewing = true;autoFocusManager = new AutoFocusManager(context, theCamera.getCamera());}}/*** Tells the camera to stop drawing preview frames.*/public synchronized void stopPreview() {if (autoFocusManager != null) {autoFocusManager.stop();autoFocusManager = null;}if (camera != null && previewing) {camera.getCamera().stopPreview();previewCallback.setHandler(null, 0);previewing = false;}}/*** Convenience method for {@link CaptureActivity}** @param newSetting if {@code true}, light should be turned on if currently off. And vice versa.*/public synchronized void setTorch(boolean newSetting) {OpenCamera theCamera = camera;if (theCamera != null) {if (newSetting != configManager.getTorchState(theCamera.getCamera())) {boolean wasAutoFocusManager = autoFocusManager != null;if (wasAutoFocusManager) {autoFocusManager.stop();autoFocusManager = null;}configManager.setTorch(theCamera.getCamera(), newSetting);if (wasAutoFocusManager) {autoFocusManager = new AutoFocusManager(context, theCamera.getCamera());autoFocusManager.start();}}}}/*** A single preview frame will be returned to the handler supplied. The data will arrive as byte[]* in the message.obj field, with width and height encoded as message.arg1 and message.arg2,* respectively.** @param handler The handler to send the message to.* @param message The what field of the message to be sent.*/public synchronized void requestPreviewFrame(Handler handler, int message) {OpenCamera theCamera = camera;if (theCamera != null && previewing) {previewCallback.setHandler(handler, message);theCamera.getCamera().setOneShotPreviewCallback(previewCallback);}}/*** Calculates the framing rect which the UI should draw to show the user where to place the* barcode. This target helps with alignment as well as forces the user to hold the device* far enough away to ensure the image will be in focus.** @return The rectangle to draw on screen in window coordinates.*/public synchronized Rect getFramingRect() {if (framingRect == null) {if (camera == null) {return null;}Point screenResolution = configManager.getScreenResolution();if (screenResolution == null) {// Called early, before init even finishedreturn null;}int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);int height = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);//保持扫描框宽高一致int finalSize = height;if (height > width) {finalSize = width;}int leftOffset = (screenResolution.x - finalSize) / 2;int topOffset = (screenResolution.y - finalSize) / 2;framingRect = new Rect(leftOffset, topOffset, leftOffset + finalSize, topOffset + finalSize);Log.d(TAG, "Calculated framing rect: " + framingRect + " width =" + width + " height = " + height +" screenResolution.x = " + screenResolution.x + " screenResolution.y = " + screenResolution.y);}return framingRect;}private static int findDesiredDimensionInRange(int resolution, int hardMin, int hardMax) {int dim = 5 * resolution / 8; // Target 5/8 of each dimensionif (dim < hardMin) {return hardMin;}if (dim > hardMax) {return hardMax;}return dim;}/*** Like {@link #getFramingRect} but coordinates are in terms of the preview frame,* not UI / screen.** @return {@link Rect} expressing barcode scan area in terms of the preview size*/public synchronized Rect getFramingRectInPreview() {if (framingRectInPreview == null) {Rect framingRect = getFramingRect();if (framingRect == null) {return null;}Rect rect = new Rect(framingRect);Point cameraResolution = configManager.getCameraResolution();Point screenResolution = configManager.getScreenResolution();if (cameraResolution == null || screenResolution == null) {// Called early, before init even finishedreturn null;}rect.left = rect.left * cameraResolution.x / screenResolution.x;rect.right = rect.right * cameraResolution.x / screenResolution.x;rect.top = rect.top * cameraResolution.y / screenResolution.y;rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;framingRectInPreview = rect;}return framingRectInPreview;}/*** Allows third party apps to specify the camera ID, rather than determine* it automatically based on available cameras and their orientation.** @param cameraId camera ID of the camera to use. A negative value means "no preference".*/public synchronized void setManualCameraId(int cameraId) {requestedCameraId = cameraId;}/*** Allows third party apps to specify the scanning rectangle dimensions, rather than determine* them automatically based on screen resolution.** @param width  The width in pixels to scan.* @param height The height in pixels to scan.*/public synchronized void setManualFramingRect(int width, int height) {if (initialized) {Point screenResolution = configManager.getScreenResolution();if (width > screenResolution.x) {width = screenResolution.x;}if (height > screenResolution.y) {height = screenResolution.y;}int leftOffset = (screenResolution.x - width) / 2;int topOffset = (screenResolution.y - height) / 2;framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);Log.d(TAG, "Calculated manual framing rect: " + framingRect);framingRectInPreview = null;} else {requestedFramingRectWidth = width;requestedFramingRectHeight = height;}}/*** A factory method to build the appropriate LuminanceSource object based on the format* of the preview buffers, as described by Camera.Parameters.** @param data   A preview frame.* @param width  The width of the image.* @param height The height of the image.* @return A PlanarYUVLuminanceSource instance.*/public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {Rect rect = getFramingRectInPreview();if (rect == null) {return null;}// Go ahead and assume it's YUV rather than die.return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,rect.width(), rect.height(), false);}public void openLight() {if (camera != null && camera.getCamera() != null) {Camera.Parameters parameter = camera.getCamera().getParameters();parameter.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);camera.getCamera().setParameters(parameter);}}public void offLight() {if (camera != null && camera.getCamera() != null) {Camera.Parameters parameter = camera.getCamera().getParameters();parameter.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);camera.getCamera().setParameters(parameter);}}}
FrontLightMode.java
public enum FrontLightMode {/** Always on. */ON,/** On only when ambient light is low. */AUTO,/** Always off. */OFF/* private static FrontLightMode parse(String modeString) {return modeString == null ? OFF : valueOf(modeString);}public static FrontLightMode readPref(SharedPreferences sharedPrefs) {return parse(sharedPrefs.getString(PreferencesActivity.KEY_FRONT_LIGHT_MODE, OFF.toString()));}*/}
PreviewCallback.java
final class PreviewCallback implements Camera.PreviewCallback {private static final String TAG = PreviewCallback.class.getSimpleName();private final CameraConfigurationManager configManager;private       Handler                    previewHandler;private       int                        previewMessage;PreviewCallback(CameraConfigurationManager configManager) {this.configManager = configManager;}void setHandler(Handler previewHandler, int previewMessage) {this.previewHandler = previewHandler;this.previewMessage = previewMessage;}@Overridepublic void onPreviewFrame(byte[] data, Camera camera) {Point cameraResolution = configManager.getCameraResolution();Handler thePreviewHandler = previewHandler;if (cameraResolution != null && thePreviewHandler != null) {//给DecodeHandler发消息Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,cameraResolution.y, data);message.sendToTarget();previewHandler = null;} else {Log.d(TAG, "Got preview callback, but no handler or resolution available");}}}
QRConstants.java
public class QRConstants {public static       boolean        vibrateEnable   = true;public static       boolean        beepEnable      = true;public static       FrontLightMode frontLightMode  = FrontLightMode.OFF;public static       boolean        disableExposure = true;public static       boolean        autoFocus       = true;public static final String         KEY_AUTO_FOCUS  = "preferences_auto_focus";}
Constant.java
public class Constant {public static final int DECODE = 1;public static final int DECODE_FAILED = 2;public static final int DECODE_SUCCEEDED = 3;public static final int LAUNCH_PRODUCT_QUERY = 4;public static final int QUIT = 5;public static final int RESTART_PREVIEW = 6;public static final int RETURN_SCAN_RESULT = 7;public static final int FLASH_OPEN = 8;public static final int FLASH_CLOSE = 9;public static final int REQUEST_IMAGE = 10;public static final String CODED_CONTENT = "codedContent";public static final String CODED_BITMAP = "codedBitmap";/*传递的zxingconfing*/public static final String INTENT_ZXING_CONFIG = "zxingConfig";}
AmbientLightManager.java
public final class AmbientLightManager implements SensorEventListener {private static final float TOO_DARK_LUX = 45.0f;private static final float BRIGHT_ENOUGH_LUX = 450.0f;private final Context       context;private       CameraManager cameraManager;private       Sensor        lightSensor;public AmbientLightManager(Context context) {this.context = context;}public void start(CameraManager cameraManager) {this.cameraManager = cameraManager;SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);if (QRConstants.frontLightMode == FrontLightMode.AUTO) {SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);if (lightSensor != null) {sensorManager.registerListener(this, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);}}}public void stop() {if (lightSensor != null) {SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);sensorManager.unregisterListener(this);cameraManager = null;lightSensor = null;}}@Overridepublic void onSensorChanged(SensorEvent sensorEvent) {float ambientLightLux = sensorEvent.values[0];if (cameraManager != null) {if (ambientLightLux <= TOO_DARK_LUX) {cameraManager.setTorch(true);} else if (ambientLightLux >= BRIGHT_ENOUGH_LUX) {cameraManager.setTorch(false);}}}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {// do nothing}}
BeepManager.java
public final class BeepManager implements MediaPlayer.OnCompletionListener,MediaPlayer.OnErrorListener, Closeable {private static final String TAG = BeepManager.class.getSimpleName();private static final float BEEP_VOLUME = 0.10f;private static final long VIBRATE_DURATION = 200L;private final Activity activity;private MediaPlayer mediaPlayer;private boolean playBeep;private boolean vibrate;public BeepManager(Activity activity) {this.activity = activity;this.mediaPlayer = null;updatePrefs();}public boolean isPlayBeep() {return playBeep;}public void setPlayBeep(boolean playBeep) {this.playBeep = playBeep;}public boolean isVibrate() {return vibrate;}public void setVibrate(boolean vibrate) {this.vibrate = vibrate;}public synchronized void updatePrefs() {if (playBeep && mediaPlayer == null) {// The volume on STREAM_SYSTEM is not adjustable, and users found it// too loud,// so we now play on the music stream.// 设置activity音量控制键控制的音频流activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);mediaPlayer = buildMediaPlayer(activity);}}/*** 开启响铃和震动*/@SuppressLint("MissingPermission")public synchronized void playBeepSoundAndVibrate() {if (playBeep && mediaPlayer != null) {mediaPlayer.start();}if (vibrate) {Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);vibrator.vibrate(VIBRATE_DURATION);}}/*** 创建MediaPlayer** @param activity* @return*/private MediaPlayer buildMediaPlayer(Context activity) {MediaPlayer mediaPlayer = new MediaPlayer();mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);// 监听是否播放完成mediaPlayer.setOnCompletionListener(this);mediaPlayer.setOnErrorListener(this);// 配置播放资源try {AssetFileDescriptor file = activity.getResources().openRawResourceFd(R.raw.beep);try {mediaPlayer.setDataSource(file.getFileDescriptor(),file.getStartOffset(), file.getLength());} finally {file.close();}// 设置音量mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);mediaPlayer.prepare();return mediaPlayer;} catch (IOException ioe) {Log.w(TAG, ioe);mediaPlayer.release();return null;}}@Overridepublic void onCompletion(MediaPlayer mp) {// When the beep has finished playing, rewind to queue up another one.mp.seekTo(0);}@Overridepublic synchronized boolean onError(MediaPlayer mp, int what, int extra) {if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {// we are finished, so put up an appropriate error toast if required// and finishactivity.finish();} else {// possibly media player error, so release and recreatemp.release();mediaPlayer = null;updatePrefs();}return true;}@Overridepublic synchronized void close() {if (mediaPlayer != null) {mediaPlayer.release();mediaPlayer = null;}}}
CaptureActivity.java
public class CaptureActivity extends Activity implements SurfaceHolder.Callback, View.OnClickListener {static {AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);//处理api 5.1以下手机不兼容问题}private static final String TAG = CaptureActivity.class.getSimpleName();private ImageView mBackmImg;private TextView  mTitle;public int REQ_ID_GALLERY = 0;public static boolean isLightOn = false;private IMResUtil mImResUtil;public static void startAction(Activity activity, Bundle bundle, int requestCode) {Intent intent = new Intent(activity, CaptureActivity.class);intent.putExtras(bundle);activity.startActivityForResult(intent, requestCode);}private CameraManager             cameraManager;private CaptureActivityHandler    handler;private ViewfinderView            viewfinderView;private boolean                   hasSurface;private Collection<BarcodeFormat> decodeFormats;private String                    characterSet;private InactivityTimer           inactivityTimer;private BeepManager               beepManager;private AmbientLightManager       ambientLightManager;private LinearLayout bottomLayout;private TextView     flashLightTv;private ImageView    flashLightIv;private LinearLayout flashLightLayout;private LinearLayout albumLayout;private ZxingConfig  config;private ImageView    img_phone;public ViewfinderView getViewfinderView() {return viewfinderView;}public Handler getHandler() {return handler;}public CameraManager getCameraManager() {return cameraManager;}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mImResUtil = new IMResUtil(this);setContentView(mImResUtil.getLayout("activity_device_qrcode_capture"));//设置浸入式状态栏setColor(this, Color.BLACK);hasSurface = false;inactivityTimer = new InactivityTimer(this);ambientLightManager = new AmbientLightManager(this);/*先获取配置信息*/try {config = (ZxingConfig) getIntent().getExtras().get(Constant.INTENT_ZXING_CONFIG);} catch (Exception e) {Log.i("config", e.toString());}if (config == null) {config = new ZxingConfig();}beepManager = new BeepManager(this);beepManager.setPlayBeep(config.isPlayBeep());beepManager.setVibrate(config.isShake());initView(getIntent().getExtras());onEvent(getIntent().getExtras());}private void initView(Bundle bundle) {//判断是否为横屏状态if ("landscape".equals(bundle.getString("portraitOrLandscape"))) {setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);}mBackmImg = (ImageView) findViewById(mImResUtil.getId("iv_qr_back"));mTitle = (TextView) findViewById(mImResUtil.getId("tv_qr_title"));viewfinderView = (ViewfinderView) findViewById(mImResUtil.getId("vv_qr_viewfinderView"));flashLightTv = (TextView) findViewById(mImResUtil.getId("flashLightTv"));bottomLayout = (LinearLayout) findViewById(mImResUtil.getId("bottomLayout"));flashLightIv = (ImageView) findViewById(mImResUtil.getId("flashLightIv"));img_phone = (ImageView) findViewById(mImResUtil.getId("img_phone"));flashLightLayout = (LinearLayout) findViewById(mImResUtil.getId("flashLightLayout"));flashLightLayout.setOnClickListener(this);albumLayout = (LinearLayout) findViewById(mImResUtil.getId("albumLayout"));albumLayout.setOnClickListener(this);}private void onEvent(Bundle bundle) {switchVisibility(bottomLayout, config.isShowbottomLayout());switchVisibility(flashLightLayout, config.isShowFlashLight());switchVisibility(albumLayout, config.isShowAlbum());flashLightIv.setImageResource(R.drawable.device_qrcode_scan_flash_off);img_phone.setImageResource(R.drawable.ic_photo);/*有闪光灯就显示手电筒按钮  否则不显示*/if (isSupportCameraLedFlash(getPackageManager())) {flashLightLayout.setVisibility(View.VISIBLE);} else {flashLightLayout.setVisibility(View.GONE);}/********************新增 END*****************************/mBackmImg.setOnClickListener(this);if (bundle == null) {return;}String titileText = bundle.getString("titileText");if (titileText != null && !titileText.isEmpty()) {mTitle.setText(titileText);}String headColor = bundle.getString("headColor");mTitle.setTextColor(Color.parseColor(headColor));float headSize = bundle.getFloat("headSize");if (headSize > 0) {mTitle.setTextSize(headSize);}}/*** 沉浸式状态栏** @param activity* @param color*/public static void setColor(Activity activity, int color) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {// 设置状态栏透明activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);// 生成一个状态栏大小的矩形View statusView = createStatusView(activity, color);// 添加 statusView 到布局中ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();decorView.addView(statusView);// 设置根布局的参数ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);rootView.setFitsSystemWindows(true);rootView.setClipToPadding(true);}}/*** 绘制一个和状态栏登高的矩形** @param activity* @param color*/private static View createStatusView(Activity activity, int color) {// 获得状态栏高度int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");int statusBarHeight = activity.getResources().getDimensionPixelSize(resourceId);View statusView = new View(activity);LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);statusView.setLayoutParams(params);statusView.setBackgroundColor(color);return statusView;}@Overridepublic void onClick(View v) {int id = v.getId();if (id == mImResUtil.getId("iv_qr_back")) {this.finish();} else if (id == mImResUtil.getId("albumLayout")) {//打开相册//            Intent intent = new Intent();//            intent.setType("image/*");//            intent.setAction(Intent.ACTION_GET_CONTENT);//            intent.addCategory(Intent.CATEGORY_OPENABLE);//            startActivityForResult(intent, REQ_ID_GALLERY);/*打开相册*/Intent intent = new Intent();intent.setAction(Intent.ACTION_PICK);intent.setType("image/*");startActivityForResult(intent, REQ_ID_GALLERY);} else if (id == mImResUtil.getId("flashLightLayout")) {//打开手电筒感应部分if (isLightOn) {isLightOn = false;cameraManager.offLight();switchFlashImg(9);} else {isLightOn = true;cameraManager.openLight();switchFlashImg(8);}}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == REQ_ID_GALLERY) {if (resultCode == RESULT_OK) {Uri uri = data.getData();if (uri != null) {String path = FileUtil.checkPicturePath(CaptureActivity.this, uri);//Device.getActivity()BitmapFactory.Options bmOptions = new BitmapFactory.Options();bmOptions.inJustDecodeBounds = false;bmOptions.inPurgeable = true;Bitmap bmp = BitmapFactory.decodeFile(path, bmOptions);decodeQRCode(bmp, this);}}}//-----------------------------------------------------if (requestCode == Constant.REQUEST_IMAGE && resultCode == RESULT_OK) {String path = ImageUtil.getImageAbsolutePath(this, data.getData());Log.e(TAG, "onActivityResult: -------二维码:path" + path);BitmapFactory.Options bmOptions = new BitmapFactory.Options();bmOptions.inJustDecodeBounds = false;bmOptions.inPurgeable = true;Bitmap bmp = BitmapFactory.decodeFile(path, bmOptions);decodeQRCode(bmp, this);}}/*** 解析二维码图片** @param bitmap   要解析的二维码图片*/public final Map<DecodeHintType, Object> HINTS = new EnumMap<>(DecodeHintType.class);@SuppressLint("StaticFieldLeak")public void decodeQRCode(final Bitmap bitmap, final Activity activity) {new AsyncTask<Void, Void, String>() {@Overrideprotected String doInBackground(Void... params) {try {int width = bitmap.getWidth();int height = bitmap.getHeight();int[] pixels = new int[width * height];bitmap.getPixels(pixels, 0, width, 0, 0, width, height);RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);Result result = new MultiFormatReader().decode(new BinaryBitmap(new HybridBinarizer(source)), HINTS);String url = "解析失败";if (result != null && result.getText() != null) {url = result.getText();}Intent resultIntent = new Intent();Bundle bundle = new Bundle();bundle.putString(Constant.CODED_CONTENT, url);resultIntent.putExtras(bundle);activity.setResult(RESULT_OK, resultIntent);CaptureActivity.this.finish();return result.getText();} catch (Exception e) {return null;}}@Overrideprotected void onPostExecute(String result) {Log.d("CaptureActivity", "result=" + result);Toast.makeText(CaptureActivity.this, "解析失败,换个图片试一下", Toast.LENGTH_LONG).show();}}.execute();}@Overrideprotected void onResume() {super.onResume();cameraManager = new CameraManager(getApplication());viewfinderView.setCameraManager(cameraManager);handler = null;beepManager.updatePrefs();ambientLightManager.start(cameraManager);inactivityTimer.onResume();decodeFormats = null;characterSet = null;SurfaceView surfaceView = (SurfaceView) findViewById(mImResUtil.getId("device_qrcode_preview_view"));SurfaceHolder surfaceHolder = surfaceView.getHolder();if (hasSurface) {initCamera(surfaceHolder);} else {surfaceHolder.addCallback(this);}}@Overrideprotected void onPause() {if (handler != null) {handler.quitSynchronously();handler = null;}inactivityTimer.onPause();ambientLightManager.stop();beepManager.close();cameraManager.closeDriver();if (!hasSurface) {SurfaceView surfaceView = (SurfaceView) findViewById(mImResUtil.getId("device_qrcode_preview_view"));SurfaceHolder surfaceHolder = surfaceView.getHolder();surfaceHolder.removeCallback(this);}super.onPause();}@Overrideprotected void onDestroy() {inactivityTimer.shutdown();super.onDestroy();}private void initCamera(SurfaceHolder surfaceHolder) {if (surfaceHolder == null) {throw new IllegalStateException("No SurfaceHolder provided");}if (cameraManager.isOpen()) {Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?");return;}try {cameraManager.openDriver(surfaceHolder);// Creating the handler starts the preview, which can also throw a RuntimeException.if (handler == null) {handler = new CaptureActivityHandler(this, decodeFormats, characterSet, cameraManager);}} catch (IOException ioe) {Log.w(TAG, ioe);} catch (RuntimeException e) {// Barcode Scanner has seen crashes in the wild of this variety:// java.?lang.?RuntimeException: Fail to connect to camera serviceLog.e(TAG, "Unexpected error initializing camera", e);}}public void drawViewfinder() {viewfinderView.drawViewfinder();}public void handleDecode(Result rawResult, Bitmap barcode, float scaleFactor) {Log.d("wxl", "rawResult=" + rawResult);boolean fromLiveScan = barcode != null;if (fromLiveScan) {String resultString = rawResult.getText();Log.e("wxl", "rawResult=" + rawResult.getText());beepManager.playBeepSoundAndVibrate();Intent resultIntent = new Intent();Bundle bundle = new Bundle();bundle.putString(Constant.CODED_CONTENT, resultString);resultIntent.putExtras(bundle);this.setResult(RESULT_OK, resultIntent);} else {//            this.setResult(RESULT_OK, resultIntent);Toast.makeText(CaptureActivity.this, "扫描失败", Toast.LENGTH_SHORT).show();}CaptureActivity.this.finish();}@Overridepublic void surfaceCreated(SurfaceHolder holder) {if (holder == null) {Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!");}if (!hasSurface) {hasSurface = true;initCamera(holder);}}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {hasSurface = false;}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}/********************新增代码 start: **************************/private void switchVisibility(View view, boolean b) {if (b) {view.setVisibility(View.VISIBLE);} else {view.setVisibility(View.GONE);}}/*** @param pm** @return 是否有闪光灯*/public static boolean isSupportCameraLedFlash(PackageManager pm) {if (pm != null) {FeatureInfo[] features = pm.getSystemAvailableFeatures();if (features != null) {for (FeatureInfo f : features) {if (f != null && PackageManager.FEATURE_CAMERA_FLASH.equals(f.name)) {return true;}}}}return false;}/*** @param flashState 切换闪光灯图片*/public void switchFlashImg(int flashState) {if (flashState == Constant.FLASH_OPEN) {flashLightIv.setImageResource(R.drawable.device_qrcode_scan_flash_on);//ic_openflashLightTv.setText("关闭闪光灯");} else {flashLightIv.setImageResource(R.drawable.device_qrcode_scan_flash_off);//ic_closeflashLightTv.setText("打开闪光灯");}}/********************新增代码 END*****************************/
}
CaptureActivityHandler.java
public final class CaptureActivityHandler extends Handler {private static final String TAG = CaptureActivityHandler.class.getSimpleName();private final CaptureActivity activity;private final DecodeThread    decodeThread;private       State           state;private final CameraManager   cameraManager;private final IMResUtil       mImResUtil;
//    private       RelativeLayout  mLightLinearLay;//LinearLayout  手电筒的线性布局private enum State {PREVIEW, SUCCESS, DONE}public CaptureActivityHandler(CaptureActivity activity, Collection<BarcodeFormat> decodeFormats, String characterSet, CameraManager cameraManager) {this.activity = activity;mImResUtil = new IMResUtil(activity);decodeThread = new DecodeThread(activity, decodeFormats, characterSet, new ViewfinderResultPointCallback(activity.getViewfinderView()));decodeThread.start();state = State.SUCCESS;// Start ourselves capturing previews and decoding.this.cameraManager = cameraManager;cameraManager.startPreview();Log.d(TAG, "CaptureActivityHandler " + CaptureActivityHandler.class.toString());restartPreviewAndDecode();}@Overridepublic void handleMessage(Message message) {int what = message.what;if (what == mImResUtil.getId("device_qrcode_restart_preview")) {restartPreviewAndDecode();} else if (what == mImResUtil.getId("device_qrcode_decode_succeeded")) {state = State.SUCCESS;Bundle bundle = message.getData();Bitmap barcode = null;float scaleFactor = 1.0f;if (bundle != null) {byte[] compressedBitmap = bundle.getByteArray(DecodeThread.BARCODE_BITMAP);if (compressedBitmap != null) {barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null);// Mutable copy:barcode = barcode.copy(Bitmap.Config.ARGB_8888, true);}scaleFactor = bundle.getFloat(DecodeThread.BARCODE_SCALED_FACTOR);}activity.handleDecode((Result) message.obj, barcode, scaleFactor);} else if (what == mImResUtil.getId("device_qrcode_decode_failed")) {state = State.PREVIEW;cameraManager.requestPreviewFrame(decodeThread.getHandler(), mImResUtil.getId("device_qrcode_decode"));} else if (what == mImResUtil.getId("device_qrcode_return_scan_result")) {activity.setResult(Activity.RESULT_OK, (Intent) message.obj);activity.finish();} else if (what == mImResUtil.getId("device_qrcode_launch_product_query")) {String url = (String) message.obj;Intent intent = new Intent(Intent.ACTION_VIEW);intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);intent.setData(Uri.parse(url));ResolveInfo resolveInfo = activity.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);String browserPackageName = null;if (resolveInfo != null && resolveInfo.activityInfo != null) {browserPackageName = resolveInfo.activityInfo.packageName;Log.d(TAG, "Using browser in package " + browserPackageName);}// Needed for default Android browser / Chrome only apparentlyif ("com.android.browser".equals(browserPackageName) || "com.android.chrome".equals(browserPackageName)) {intent.setPackage(browserPackageName);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.putExtra(Browser.EXTRA_APPLICATION_ID, browserPackageName);}try {activity.startActivity(intent);} catch (ActivityNotFoundException ignored) {Log.w(TAG, "Can't find anything to handle VIEW of URI " + url);}}}public void quitSynchronously() {state = State.DONE;cameraManager.stopPreview();Message quit = Message.obtain(decodeThread.getHandler(), mImResUtil.getId("device_qrcode_quit"));quit.sendToTarget();try {// Wait at most half a second; should be enough time, and onPause() will timeout quicklydecodeThread.join(500L);} catch (InterruptedException e) {// continue}// Be absolutely sure we don't send any queued up messagesremoveMessages(mImResUtil.getId("device_qrcode_decode_succeeded"));removeMessages(mImResUtil.getId("device_qrcode_decode_failed"));}private void restartPreviewAndDecode() {if (state == State.SUCCESS) {state = State.PREVIEW;//decodeThread.getHandler()拿到DecodeHandlercameraManager.requestPreviewFrame(decodeThread.getHandler(), mImResUtil.getId("device_qrcode_decode"));activity.drawViewfinder();}}}
DecodeFormatManager.java
final class DecodeFormatManager {private static final Pattern COMMA_PATTERN = Pattern.compile(",");//  static final Set<BarcodeFormat> PRODUCT_FORMATS;
//  static final Set<BarcodeFormat> INDUSTRIAL_FORMATS;
//  private static final Set<BarcodeFormat> ONE_D_FORMATS;static final Set<BarcodeFormat> QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE);
//  static final Set<BarcodeFormat> DATA_MATRIX_FORMATS = EnumSet.of(BarcodeFormat.DATA_MATRIX);
//  static final Set<BarcodeFormat> AZTEC_FORMATS = EnumSet.of(BarcodeFormat.AZTEC);
//  static final Set<BarcodeFormat> PDF417_FORMATS = EnumSet.of(BarcodeFormat.PDF_417);/*static {PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A,BarcodeFormat.UPC_E,BarcodeFormat.EAN_13,BarcodeFormat.EAN_8,BarcodeFormat.RSS_14,BarcodeFormat.RSS_EXPANDED);INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39,BarcodeFormat.CODE_93,BarcodeFormat.CODE_128,BarcodeFormat.ITF,BarcodeFormat.CODABAR);ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS);ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS);}*/private static final Map<String,Set<BarcodeFormat>> FORMATS_FOR_MODE;static {FORMATS_FOR_MODE = new HashMap<>();
//    FORMATS_FOR_MODE.put(Intents.Scan.ONE_D_MODE, ONE_D_FORMATS);
//    FORMATS_FOR_MODE.put(Intents.Scan.PRODUCT_MODE, PRODUCT_FORMATS);FORMATS_FOR_MODE.put(Intents.Scan.QR_CODE_MODE, QR_CODE_FORMATS);
//    FORMATS_FOR_MODE.put(Intents.Scan.DATA_MATRIX_MODE, DATA_MATRIX_FORMATS);
//    FORMATS_FOR_MODE.put(Intents.Scan.AZTEC_MODE, AZTEC_FORMATS);
//    FORMATS_FOR_MODE.put(Intents.Scan.PDF417_MODE, PDF417_FORMATS);}private DecodeFormatManager() {}static Set<BarcodeFormat> parseDecodeFormats(Intent intent) {Iterable<String> scanFormats = null;CharSequence scanFormatsString = intent.getStringExtra(Intents.Scan.FORMATS);if (scanFormatsString != null) {scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString));}return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE));}static Set<BarcodeFormat> parseDecodeFormats(Uri inputUri) {List<String> formats = inputUri.getQueryParameters(Intents.Scan.FORMATS);if (formats != null && formats.size() == 1 && formats.get(0) != null){formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0)));}return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE));}private static Set<BarcodeFormat> parseDecodeFormats(Iterable<String> scanFormats, String decodeMode) {if (scanFormats != null) {Set<BarcodeFormat> formats = EnumSet.noneOf(BarcodeFormat.class);try {for (String format : scanFormats) {formats.add(BarcodeFormat.valueOf(format));}return formats;} catch (IllegalArgumentException iae) {// ignore it then}}if (decodeMode != null) {return FORMATS_FOR_MODE.get(decodeMode);}return null;}}
DecodeHandler.java
final class DecodeHandler extends Handler {private static final String TAG = DecodeHandler.class.getSimpleName();public static boolean isWeakLight  = false;private final CaptureActivity   activity;private final MultiFormatReader multiFormatReader;private boolean running = true;private final IMResUtil mImResUtil;DecodeHandler(CaptureActivity activity, Map<DecodeHintType, Object> hints) {multiFormatReader = new MultiFormatReader();multiFormatReader.setHints(hints);this.activity = activity;mImResUtil = new IMResUtil(activity);}@Overridepublic void handleMessage(Message message) {if (!running) {return;}int what = message.what;if (what == mImResUtil.getId("device_qrcode_decode")) {decode((byte[]) message.obj, message.arg1, message.arg2);} else if (what == mImResUtil.getId("device_qrcode_quit")) {isWeakLight  = false;CaptureActivity.isLightOn = false;running = false;Looper.myLooper().quit();}}/*** Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,* reuse the same reader objects from one decode to the next.** @param data   The YUV preview frame.* @param width  The width of the preview frame.* @param height The height of the preview frame.*/private void decode(byte[] data, int width, int height) {Log.i(TAG, "decode");//弱光检测analysisColor(data,width,height);long start = System.currentTimeMillis();Result rawResult = null;PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, width, height);if (source != null) {BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));try {rawResult = multiFormatReader.decodeWithState(bitmap);} catch (ReaderException re) {// continue} finally {multiFormatReader.reset();}}Handler handler = activity.getHandler();//拿到CaptureActivityHandlerLog.d(TAG, "Found handler " + handler);if (rawResult != null) {// Don't log the barcode contents for security.long end = System.currentTimeMillis();Log.d(TAG, "Found barcode in " + (end - start) + " ms");if (handler != null) {//给CaptureActivityHandler发消息Message message = Message.obtain(handler, mImResUtil.getId("device_qrcode_decode_succeeded"), rawResult);Bundle bundle = new Bundle();bundleThumbnail(source, bundle);message.setData(bundle);message.sendToTarget();}} else {if (handler != null) {Message message = Message.obtain(handler, mImResUtil.getId("device_qrcode_decode_failed"));message.sendToTarget();}}}private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) {int[] pixels = source.renderThumbnail();int width = source.getThumbnailWidth();int height = source.getThumbnailHeight();Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888);ByteArrayOutputStream out = new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);bundle.putByteArray(DecodeThread.BARCODE_BITMAP, out.toByteArray());bundle.putFloat(DecodeThread.BARCODE_SCALED_FACTOR, (float) width / source.getWidth());}private  int[] decodeYUV420SP(byte[] yuv420sp, int width, int height) {final int frameSize = width * height;int rgb[] = new int[width * height];for (int j = 0, yp = 0; j < height; j++) {int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;for (int i = 0; i < width; i++, yp++) {int y = (0xff & ((int) yuv420sp[yp])) - 16;if (y < 0) y = 0;if ((i & 1) == 0) {v = (0xff & yuv420sp[uvp++]) - 128;u = (0xff & yuv420sp[uvp++]) - 128;}int y1192 = 1192 * y;int r = (y1192 + 1634 * v);int g = (y1192 - 833 * v - 400 * u);int b = (y1192 + 2066 * u);if (r < 0) r = 0;else if (r > 262143) r = 262143;if (g < 0) g = 0;else if (g > 262143) g = 262143;if (b < 0) b = 0;else if (b > 262143) b = 262143;rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) &0xff00) | ((b >> 10) & 0xff);}}return rgb;}private  int getAverageColor(Bitmap bitmap) {int redBucket = 0;int greenBucket = 0;int blueBucket = 0;int pixelCount = 0;for (int y = 0; y < bitmap.getHeight(); y++) {for (int x = 0; x < bitmap.getWidth(); x++) {int c = bitmap.getPixel(x, y);pixelCount++;redBucket += Color.red(c);greenBucket += Color.green(c);blueBucket += Color.blue(c);}}int averageColor = Color.rgb(redBucket / pixelCount, greenBucket/ pixelCount, blueBucket / pixelCount);return averageColor;}//分析预览帧中图片的arg 取平均值public  void analysisColor(byte[] data, int width, int height) {int[] rgb = decodeYUV420SP(data, width / 8, height / 8);Bitmap bmp = Bitmap.createBitmap(rgb, width / 8, height / 8, Bitmap.Config.ARGB_8888);//这里报错if (bmp != null) {//取以中心点宽高10像素的图片来分析Bitmap resizeBitmap = Bitmap.createBitmap(bmp, bmp.getWidth() / 2, bmp.getHeight() / 2, 10, 10);float color = (float) getAverageColor(resizeBitmap);DecimalFormat decimalFormat1 = new DecimalFormat("0.00");String percent = decimalFormat1.format(color / -16777216);float floatPercent = Float.parseFloat(percent);isWeakLight = floatPercent >= 0.99 && floatPercent <= 1.00;
//            Log.i(TAG,"isWeakLight "+isWeakLight);if (null != resizeBitmap) {resizeBitmap.recycle();}bmp.recycle();}}
}
DecodeHintManager.java
final class DecodeHintManager {private static final String TAG = DecodeHintManager.class.getSimpleName();// This pattern is used in decoding integer arrays.private static final Pattern COMMA = Pattern.compile(",");private DecodeHintManager() {}/*** <p>Split a query string into a list of name-value pairs.</p>* * <p>This is an alternative to the {@link Uri#getQueryParameterNames()} and* {@link Uri#getQueryParameters(String)}, which are quirky and not suitable* for exist-only Uri parameters.</p>* * <p>This method ignores multiple parameters with the same name and returns the* first one only. This is technically incorrect, but should be acceptable due* to the method of processing Hints: no multiple values for a hint.</p>* * @param query query to split* @return name-value pairs*/private static Map<String,String> splitQuery(String query) {Map<String,String> map = new HashMap<>();int pos = 0;while (pos < query.length()) {if (query.charAt(pos) == '&') {// Skip consecutive ampersand separators.pos ++;continue;}int amp = query.indexOf('&', pos);int equ = query.indexOf('=', pos);if (amp < 0) {// This is the last element in the query, no more ampersand elements.String name;String text;if (equ < 0) {// No equal signname = query.substring(pos);name = name.replace('+', ' '); // Preemptively decode +name = Uri.decode(name);text = "";} else {// Split name and text.name = query.substring(pos, equ);name = name.replace('+', ' '); // Preemptively decode +name = Uri.decode(name);text = query.substring(equ + 1);text = text.replace('+', ' '); // Preemptively decode +text = Uri.decode(text);}if (!map.containsKey(name)) {map.put(name, text);}break;}if (equ < 0 || equ > amp) {// No equal sign until the &: this is a simple parameter with no value.String name = query.substring(pos, amp);name = name.replace('+', ' '); // Preemptively decode +name = Uri.decode(name);if (!map.containsKey(name)) {map.put(name, "");}pos = amp + 1;continue;}String name = query.substring(pos, equ);name = name.replace('+', ' '); // Preemptively decode +name = Uri.decode(name);String text = query.substring(equ+1, amp);text = text.replace('+', ' '); // Preemptively decode +text = Uri.decode(text);if (!map.containsKey(name)) {map.put(name, text);}pos = amp + 1;}return map;}static Map<DecodeHintType,?> parseDecodeHints(Uri inputUri) {String query = inputUri.getEncodedQuery();if (query == null || query.isEmpty()) {return null;}// Extract parametersMap<String, String> parameters = splitQuery(query);Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);for (DecodeHintType hintType: DecodeHintType.values()) {if (hintType == DecodeHintType.CHARACTER_SET ||hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||hintType == DecodeHintType.POSSIBLE_FORMATS) {continue; // This hint is specified in another way}String parameterName = hintType.name();String parameterText = parameters.get(parameterName);if (parameterText == null) {continue;}if (hintType.getValueType().equals(Object.class)) {// This is an unspecified type of hint content. Use the value as is.// TODO: Can we make a different assumption on this?hints.put(hintType, parameterText);continue;}if (hintType.getValueType().equals(Void.class)) {// Void hints are just flags: use the constant specified by DecodeHintTypehints.put(hintType, Boolean.TRUE);continue;}if (hintType.getValueType().equals(String.class)) {// A string hint: use the decoded value.hints.put(hintType, parameterText);continue;}if (hintType.getValueType().equals(Boolean.class)) {// A boolean hint: a few values for false, everything else is true.// An empty parameter is simply a flag-style parameter, assuming trueif (parameterText.isEmpty()) {hints.put(hintType, Boolean.TRUE);} else if ("0".equals(parameterText) || "false".equalsIgnoreCase(parameterText) || "no".equalsIgnoreCase(parameterText)) {hints.put(hintType, Boolean.FALSE);} else {hints.put(hintType, Boolean.TRUE);}continue;}if (hintType.getValueType().equals(int[].class)) {// An integer array. Used to specify valid lengths.// Strip a trailing comma as in Java style array initialisers.if (!parameterText.isEmpty() && parameterText.charAt(parameterText.length() - 1) == ',') {parameterText = parameterText.substring(0, parameterText.length() - 1);}String[] values = COMMA.split(parameterText);int[] array = new int[values.length];for (int i = 0; i < values.length; i++) {try {array[i] = Integer.parseInt(values[i]);} catch (NumberFormatException ignored) {Log.w(TAG, "Skipping array of integers hint " + hintType + " due to invalid numeric value: '" + values[i] + '\'');array = null;break;}}if (array != null) {hints.put(hintType, array);}continue;} Log.w(TAG, "Unsupported hint type '" + hintType + "' of type " + hintType.getValueType());}Log.i(TAG, "Hints from the URI: " + hints);return hints;}static Map<DecodeHintType, Object> parseDecodeHints(Intent intent) {Bundle extras = intent.getExtras();if (extras == null || extras.isEmpty()) {return null;}Map<DecodeHintType,Object> hints = new EnumMap<>(DecodeHintType.class);for (DecodeHintType hintType: DecodeHintType.values()) {if (hintType == DecodeHintType.CHARACTER_SET ||hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||hintType == DecodeHintType.POSSIBLE_FORMATS) {continue; // This hint is specified in another way}String hintName = hintType.name();if (extras.containsKey(hintName)) {if (hintType.getValueType().equals(Void.class)) {// Void hints are just flags: use the constant specified by the DecodeHintTypehints.put(hintType, Boolean.TRUE);} else {Object hintData = extras.get(hintName);if (hintType.getValueType().isInstance(hintData)) {hints.put(hintType, hintData);} else {Log.w(TAG, "Ignoring hint " + hintType + " because it is not assignable from " + hintData);}}}}Log.i(TAG, "Hints from the Intent: " + hints);return hints;}}
DecodeThread.java
final class DecodeThread extends Thread {public static final String BARCODE_BITMAP = "barcode_bitmap";public static final String BARCODE_SCALED_FACTOR = "barcode_scaled_factor";private final CaptureActivity             activity;private final Map<DecodeHintType, Object> hints;private Handler                           handler;private final CountDownLatch              handlerInitLatch;public DecodeThread(CaptureActivity activity,Collection<BarcodeFormat> decodeFormats,String characterSet,ResultPointCallback resultPointCallback) {this.activity = activity;handlerInitLatch = new CountDownLatch(1);hints = new EnumMap<>(DecodeHintType.class);// The prefs can't change while the thread is running, so pick them up once here.if (decodeFormats == null || decodeFormats.isEmpty()) {
//            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);decodeFormats = EnumSet.noneOf(BarcodeFormat.class);/*if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_1D_PRODUCT, true)) {decodeFormats.addAll(DecodeFormatManager.PRODUCT_FORMATS);}if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_1D_INDUSTRIAL, true)) {decodeFormats.addAll(DecodeFormatManager.INDUSTRIAL_FORMATS);}*/
//            if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_QR, true)) {decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
//            }/* if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_DATA_MATRIX, true)) {decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);}if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_AZTEC, false)) {decodeFormats.addAll(DecodeFormatManager.AZTEC_FORMATS);}if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_PDF417, false)) {decodeFormats.addAll(DecodeFormatManager.PDF417_FORMATS);}*/}hints.put(DecodeHintType.POSSIBLE_FORMATS, DecodeFormatManager.QR_CODE_FORMATS);if (characterSet != null) {hints.put(DecodeHintType.CHARACTER_SET, characterSet);}hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback);Log.i("DecodeThread", "Hints: " + hints);}Handler getHandler() {try {handlerInitLatch.await();} catch (InterruptedException ie) {// continue?}return handler;}@Overridepublic void run() {Looper.prepare();handler = new DecodeHandler(activity, hints);handlerInitLatch.countDown();Looper.loop();}}
ImageUtil.java
public class ImageUtil {@TargetApi(19)public static String getImageAbsolutePath(Context context, Uri imageUri) {if (context == null || imageUri == null)return null;if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, imageUri)) {if (isExternalStorageDocument(imageUri)) {String docId = DocumentsContract.getDocumentId(imageUri);String[] split = docId.split(":");String type = split[0];if ("primary".equalsIgnoreCase(type)) {return Environment.getExternalStorageDirectory() + "/" + split[1];}} else if (isDownloadsDocument(imageUri)) {String id = DocumentsContract.getDocumentId(imageUri);Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));return getDataColumn(context, contentUri, null, null);} else if (isMediaDocument(imageUri)) {String docId = DocumentsContract.getDocumentId(imageUri);String[] split = docId.split(":");String type = split[0];Uri contentUri = null;if ("image".equals(type)) {contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;} else if ("video".equals(type)) {contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;} else if ("audio".equals(type)) {contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;}String selection = MediaStore.Images.Media._ID + "=?";String[] selectionArgs = new String[]{split[1]};return getDataColumn(context, contentUri, selection, selectionArgs);}} // MediaStore (and general)else if ("content".equalsIgnoreCase(imageUri.getScheme())) {// Return the remote addressif (isGooglePhotosUri(imageUri))return imageUri.getLastPathSegment();return getDataColumn(context, imageUri, null, null);}// Fileelse if ("file".equalsIgnoreCase(imageUri.getScheme())) {return imageUri.getPath();}return null;}public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {Cursor cursor = null;String column = MediaStore.Images.Media.DATA;String[] projection = {column};try {cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);if (cursor != null && cursor.moveToFirst()) {int index = cursor.getColumnIndexOrThrow(column);return cursor.getString(index);}} finally {if (cursor != null)cursor.close();}return null;}/*** @param uri The Uri to check.* @return Whether the Uri authority is ExternalStorageProvider.*/public static boolean isExternalStorageDocument(Uri uri) {return "com.android.externalstorage.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is DownloadsProvider.*/public static boolean isDownloadsDocument(Uri uri) {return "com.android.providers.downloads.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is MediaProvider.*/public static boolean isMediaDocument(Uri uri) {return "com.android.providers.media.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is Google Photos.*/public static boolean isGooglePhotosUri(Uri uri) {return "com.google.android.apps.photos.content".equals(uri.getAuthority());}
}
InactivityTimer.java
public final class InactivityTimer {private static final String TAG = InactivityTimer.class.getSimpleName();private static final long INACTIVITY_DELAY_MS = 5 * 60 * 1000L;private final Activity activity;private final BroadcastReceiver powerStatusReceiver;private boolean registered;private AsyncTask<Object, Object, Object> inactivityTask;public InactivityTimer(Activity activity) {this.activity = activity;powerStatusReceiver = new PowerStatusReceiver();registered = false;onActivity();}public synchronized void onActivity() {cancel();inactivityTask = new InactivityAsyncTask();inactivityTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);}public synchronized void onPause() {cancel();if (registered) {activity.unregisterReceiver(powerStatusReceiver);registered = false;} else {Log.w(TAG, "PowerStatusReceiver was never registered?");}}public synchronized void onResume() {if (registered) {Log.w(TAG, "PowerStatusReceiver was already registered?");} else {activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));registered = true;}onActivity();}private synchronized void cancel() {AsyncTask<?, ?, ?> task = inactivityTask;if (task != null) {task.cancel(true);inactivityTask = null;}}public void shutdown() {cancel();}private final class PowerStatusReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {// 0 indicates that we're on batteryboolean onBatteryNow = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) <= 0;if (onBatteryNow) {InactivityTimer.this.onActivity();} else {InactivityTimer.this.cancel();}}}}private final class InactivityAsyncTask extends AsyncTask<Object, Object, Object> {@Overrideprotected Object doInBackground(Object... objects) {try {Thread.sleep(INACTIVITY_DELAY_MS);Log.i(TAG, "Finishing activity due to inactivity");activity.finish();} catch (InterruptedException e) {// continue without killing}return null;}}}
Intents.java
public final class Intents {private Intents() {}public static final class Scan {/*** Send this intent to open the Barcodes app in scanning mode, find a barcode, and return* the results.*/public static final String ACTION = "com.google.zxing.client.android.SCAN";/*** By default, sending this will decode all barcodes that we understand. However it* may be useful to limit scanning to certain formats. Use* {@link android.content.Intent#putExtra(String, String)} with one of the values below.** Setting this is effectively shorthand for setting explicit formats with {@link #FORMATS}.* It is overridden by that setting.*/public static final String MODE = "SCAN_MODE";/*** Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get* prices, reviews, etc. for products.*/public static final String PRODUCT_MODE = "PRODUCT_MODE";/*** Decode only 1D barcodes.*/public static final String ONE_D_MODE = "ONE_D_MODE";/*** Decode only QR codes.*/public static final String QR_CODE_MODE = "QR_CODE_MODE";/*** Decode only Data Matrix codes.*/public static final String DATA_MATRIX_MODE = "DATA_MATRIX_MODE";/*** Decode only Aztec.*/public static final String AZTEC_MODE = "AZTEC_MODE";/*** Decode only PDF417.*/public static final String PDF417_MODE = "PDF417_MODE";/*** Comma-separated list of formats to scan for. The values must match the names of* {@link com.google.zxing.BarcodeFormat}s, e.g. {@link com.google.zxing.BarcodeFormat#EAN_13}.* Example: "EAN_13,EAN_8,QR_CODE". This overrides {@link #MODE}.*/public static final String FORMATS = "SCAN_FORMATS";/*** Optional parameter to specify the id of the camera from which to recognize barcodes.* Overrides the default camera that would otherwise would have been selected.* If provided, should be an int.*/public static final String CAMERA_ID = "SCAN_CAMERA_ID";/*** @see com.google.zxing.DecodeHintType#CHARACTER_SET*/public static final String CHARACTER_SET = "CHARACTER_SET";/*** Optional parameters to specify the width and height of the scanning rectangle in pixels.* The app will try to honor these, but will clamp them to the size of the preview frame.* You should specify both or neither, and pass the size as an int.*/public static final String WIDTH = "SCAN_WIDTH";public static final String HEIGHT = "SCAN_HEIGHT";/*** Desired duration in milliseconds for which to pause after a successful scan before* returning to the calling intent. Specified as a long, not an integer!* For example: 1000L, not 1000.*/public static final String RESULT_DISPLAY_DURATION_MS = "RESULT_DISPLAY_DURATION_MS";/*** Prompt to show on-screen when scanning by intent. Specified as a {@link String}.*/public static final String PROMPT_MESSAGE = "PROMPT_MESSAGE";/*** If a barcode is found, Barcodes returns {@link android.app.Activity#RESULT_OK} to* {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)}* of the app which requested the scan via* {@link android.app.Activity#startActivityForResult(android.content.Intent, int)}* The barcodes contents can be retrieved with* {@link android.content.Intent#getStringExtra(String)}.* If the user presses Back, the result code will be {@link android.app.Activity#RESULT_CANCELED}.*/public static final String RESULT = "SCAN_RESULT";/*** Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_FORMAT}* to determine which barcode format was found.* See {@link com.google.zxing.BarcodeFormat} for possible values.*/public static final String RESULT_FORMAT = "SCAN_RESULT_FORMAT";/*** Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_UPC_EAN_EXTENSION}* to return the content of any UPC extension barcode that was also found. Only applicable* to {@link com.google.zxing.BarcodeFormat#UPC_A} and {@link com.google.zxing.BarcodeFormat#EAN_13}* formats.*/public static final String RESULT_UPC_EAN_EXTENSION = "SCAN_RESULT_UPC_EAN_EXTENSION";/*** Call {@link android.content.Intent#getByteArrayExtra(String)} with {@link #RESULT_BYTES}* to get a {@code byte[]} of raw bytes in the barcode, if available.*/public static final String RESULT_BYTES = "SCAN_RESULT_BYTES";/*** Key for the value of {@link com.google.zxing.ResultMetadataType#ORIENTATION}, if available.* Call {@link android.content.Intent#getIntArrayExtra(String)} with {@link #RESULT_ORIENTATION}.*/public static final String RESULT_ORIENTATION = "SCAN_RESULT_ORIENTATION";/*** Key for the value of {@link com.google.zxing.ResultMetadataType#ERROR_CORRECTION_LEVEL}, if available.* Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_ERROR_CORRECTION_LEVEL}.*/public static final String RESULT_ERROR_CORRECTION_LEVEL = "SCAN_RESULT_ERROR_CORRECTION_LEVEL";/*** Prefix for keys that map to the values of {@link com.google.zxing.ResultMetadataType#BYTE_SEGMENTS},* if available. The actual values will be set under a series of keys formed by adding 0, 1, 2, ...* to this prefix. So the first byte segment is under key "SCAN_RESULT_BYTE_SEGMENTS_0" for example.* Call {@link android.content.Intent#getByteArrayExtra(String)} with these keys.*/public static final String RESULT_BYTE_SEGMENTS_PREFIX = "SCAN_RESULT_BYTE_SEGMENTS_";/*** Setting this to false will not save scanned codes in the history. Specified as a {@code boolean}.*/public static final String SAVE_HISTORY = "SAVE_HISTORY";private Scan() {}}public static final class History {public static final String ITEM_NUMBER = "ITEM_NUMBER";private History() {}}public static final class Encode {/*** Send this intent to encode a piece of data as a QR code and display it full screen, so* that another person can scan the barcode from your screen.*/public static final String ACTION = "com.google.zxing.client.android.ENCODE";/*** The data to encode. Use {@link android.content.Intent#putExtra(String, String)} or* {@link android.content.Intent#putExtra(String, android.os.Bundle)},* depending on the type and format specified. Non-QR Code formats should* just use a String here. For QR Code, see Contents for details.*/public static final String DATA = "ENCODE_DATA";/*** The type of data being supplied if the format is QR Code. Use* {@link android.content.Intent#putExtra(String, String)} with one of {@link Contents.Type}.*/public static final String TYPE = "ENCODE_TYPE";/*** The barcode format to be displayed. If this isn't specified or is blank,* it defaults to QR Code. Use {@link android.content.Intent#putExtra(String, String)}, where* format is one of {@link com.google.zxing.BarcodeFormat}.*/public static final String FORMAT = "ENCODE_FORMAT";/*** Normally the contents of the barcode are displayed to the user in a TextView. Setting this* boolean to false will hide that TextView, showing only the encode barcode.*/public static final String SHOW_CONTENTS = "ENCODE_SHOW_CONTENTS";private Encode() {}}public static final class SearchBookContents {/*** Use Google Book Search to search the contents of the book provided.*/public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS";/*** The book to search, identified by ISBN number.*/public static final String ISBN = "ISBN";/*** An optional field which is the text to search for.*/public static final String QUERY = "QUERY";private SearchBookContents() {}}public static final class WifiConnect {/*** Internal intent used to trigger connection to a wi-fi network.*/public static final String ACTION = "com.google.zxing.client.android.WIFI_CONNECT";/*** The network to connect to, all the configuration provided here.*/public static final String SSID = "SSID";/*** The network to connect to, all the configuration provided here.*/public static final String TYPE = "TYPE";/*** The network to connect to, all the configuration provided here.*/public static final String PASSWORD = "PASSWORD";private WifiConnect() {}}public static final class Share {/*** Give the user a choice of items to encode as a barcode, then render it as a QR Code and* display onscreen for a friend to scan with their phone.*/public static final String ACTION = "com.google.zxing.client.android.SHARE";private Share() {}}
}
ViewfinderResultPointCallback.java
final class ViewfinderResultPointCallback implements ResultPointCallback {private final ViewfinderView viewfinderView;ViewfinderResultPointCallback(ViewfinderView viewfinderView) {this.viewfinderView = viewfinderView;}@Overridepublic void foundPossibleResultPoint(ResultPoint point) {viewfinderView.addPossibleResultPoint(point);}}
CodeCreator.java
public class CodeCreator {/*logo*/private static Bitmap logoBitmap;/*生成二维码*/public static Bitmap createQRCode(String content, int w, int h,Bitmap logo) throws WriterException {if (TextUtils.isEmpty(content)) {return null;}/*偏移量*/int offsetX = w / 2;int offsetY = h / 2;/*生成logo*/if (logo!=null){Matrix matrix = new Matrix();float scaleFactor = Math.min(w * 1.0f / 5 / logo.getWidth(), h * 1.0f / 5 /logo.getHeight());matrix.postScale(scaleFactor,scaleFactor);logoBitmap= Bitmap.createBitmap(logo, 0, 0, logo.getWidth(),   logo.getHeight(), matrix, true);}/*如果log不为null,重新计算偏移量*/int logoW = 0;int logoH = 0;if (logoBitmap != null) {logoW = logoBitmap.getWidth();logoH = logoBitmap.getHeight();offsetX = (w - logoW) / 2;offsetY = (h - logoH) / 2;}/*指定为UTF-8*/Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();hints.put(EncodeHintType.CHARACTER_SET, "utf-8");//容错级别hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);//设置空白边距的宽度hints.put(EncodeHintType.MARGIN, 0);// 生成二维矩阵,编码时指定大小,不要生成了图片以后再进行缩放,这样会模糊导致识别失败BitMatrix matrix = new MultiFormatWriter().encode(content,BarcodeFormat.QR_CODE, w, h, hints);// 二维矩阵转为一维像素数组,也就是一直横着排了int[] pixels = new int[w * h];for (int y = 0; y < h; y++) {for (int x = 0; x < w; x++) {if(x >= offsetX && x < offsetX + logoW && y>= offsetY && y < offsetY + logoH){int pixel = logoBitmap.getPixel(x-offsetX,y-offsetY);if(pixel == 0){if(matrix.get(x, y)){pixel = 0xff000000;}else{pixel = 0xffffffff;}}pixels[y * w + x] = pixel;}else{if (matrix.get(x, y)) {pixels[y * w + x] = 0xff000000;} else {pixels[y * w + x] = 0xffffffff;}}}}Bitmap bitmap = Bitmap.createBitmap(w, h,Bitmap.Config.ARGB_8888);bitmap.setPixels(pixels, 0, w, 0, 0, w, h);return bitmap;}}
QRCodeEncoder.java
public final class QRCodeEncoder {private static final String TAG = QRCodeEncoder.class.getSimpleName();private static final int WHITE = 0xFFFFFFFF;private static final int BLACK = 0xFF000000;public static Bitmap encodeAsBitmap(String contents, int dimension) throws WriterException {String contentsToEncode = contents;if (contentsToEncode == null) {return null;}Map<EncodeHintType, Object> hints = null;String encoding = guessAppropriateEncoding(contentsToEncode);if (encoding != null) {hints = new EnumMap<>(EncodeHintType.class);hints.put(EncodeHintType.CHARACTER_SET, encoding);}BitMatrix result;try {result = new MultiFormatWriter().encode(contentsToEncode, BarcodeFormat.QR_CODE, dimension, dimension, hints);} catch (IllegalArgumentException iae) {// Unsupported formatreturn null;}int width = result.getWidth();int height = result.getHeight();int[] pixels = new int[width * height];for (int y = 0; y < height; y++) {int offset = y * width;for (int x = 0; x < width; x++) {pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;}}Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);bitmap.setPixels(pixels, 0, width, 0, 0, width, height);return bitmap;}private static String guessAppropriateEncoding(CharSequence contents) {// Very crude at the momentfor (int i = 0; i < contents.length(); i++) {if (contents.charAt(i) > 0xFF) {return "UTF-8";}}return null;}}
ViewfinderResultPointCallback.java
public final class ViewfinderResultPointCallback implements ResultPointCallback {private final ViewfinderView viewfinderView;public ViewfinderResultPointCallback(ViewfinderView viewfinderView) {this.viewfinderView = viewfinderView;}@Overridepublic void foundPossibleResultPoint(ResultPoint point) {viewfinderView.addPossibleResultPoint(point);}}
ViewfinderView.java
public final class ViewfinderView extends View{private static final long ANIMATION_DELAY = 10;private static final int CORNER_RECT_HEIGHT = 40;private static final int CORNER_RECT_WIDTH = 8;private static final int OPAQUE = 255;private static final int[] SCANNER_ALPHA = new int[]{0, 64, 128, 192, OPAQUE, 192, 128, 64};private static final int SCANNER_LINE_HEIGHT = 10;private static final int SCANNER_LINE_MOVE_DISTANCE = 5;public static int scannerEnd = 0;public static int scannerStart = 0;private       CameraManager           cameraManager;private final int                     cornerColor;private final int                     frameColor;private       String                  labelText;private       int                     labelTextColor;private       float                   labelTextSize;private final int                     laserColor;private       Collection<ResultPoint> lastPossibleResultPoints;private final IMResUtil               mImResUtil;private final int                     maskColor;private final Paint paint = new Paint();private Collection<ResultPoint> possibleResultPoints;private Bitmap                  resultBitmap;private final int               resultColor;private final int               resultPointColor;private int                     scannerAlpha;public ViewfinderView(Context context, AttributeSet attrs) {super(context, attrs);this.mImResUtil = new IMResUtil(context);TypedArray array = context.obtainStyledAttributes(attrs, this.mImResUtil.getStyleableArray("ViewfinderView"));this.laserColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_laser_color"), 65280);this.cornerColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_corner_color"), 65280);this.frameColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_frame_color"), 16777215);this.resultPointColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_result_point_color"), -1056964864);this.maskColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_mask_color"), 1610612736);this.resultColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_result_color"), -1342177280);this.labelTextColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_label_text_color"), -1862270977);this.labelText = array.getString(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_label_text"));this.labelTextSize = (float) array.getDimensionPixelSize(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_label_text_size"), (int) TypedValue.applyDimension(2, 16.0f, getResources().getDisplayMetrics()));this.paint.setAntiAlias(true);this.scannerAlpha = 0;this.possibleResultPoints = new HashSet(5);}public void setCameraManager(CameraManager cameraManager) {this.cameraManager = cameraManager;}public void onDraw(Canvas canvas) {Rect frame = this.cameraManager.getFramingRect();if (frame != null) {if (scannerStart == 0 || scannerEnd == 0) {scannerStart = frame.top;scannerEnd = frame.bottom;}drawExterior(canvas, frame, canvas.getWidth(), canvas.getHeight());if (this.resultBitmap != null) {this.paint.setAlpha(OPAQUE);canvas.drawBitmap(this.resultBitmap, (float) frame.left, (float) frame.top, this.paint);return;}drawFrame(canvas, frame);drawCorner(canvas, frame);drawLaserScanner(canvas, frame);drawTextInfo(canvas, frame);Collection<ResultPoint> currentPossible = this.possibleResultPoints;Collection<ResultPoint> currentLast = this.lastPossibleResultPoints;if (currentPossible.isEmpty()) {this.lastPossibleResultPoints = null;} else {this.possibleResultPoints = new HashSet(5);this.lastPossibleResultPoints = currentPossible;this.paint.setAlpha(OPAQUE);this.paint.setColor(this.resultPointColor);for (ResultPoint point : currentPossible) {canvas.drawCircle(((float) frame.left) + point.getX(), ((float) frame.top) + point.getY(), 6.0f, this.paint);}}if (currentLast != null) {this.paint.setAlpha(127);this.paint.setColor(this.resultPointColor);for (ResultPoint point2 : currentLast) {canvas.drawCircle(((float) frame.left) + point2.getX(), ((float) frame.top) + point2.getY(), 3.0f, this.paint);}}postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);}}private void drawTextInfo(Canvas canvas, Rect frame) {this.paint.setColor(this.labelTextColor);this.paint.setTextSize(TypedValue.applyDimension(2, this.labelTextSize, getResources().getDisplayMetrics()));this.paint.setTextAlign(Align.CENTER);}private void drawCorner(Canvas canvas, Rect frame) {this.paint.setColor(this.cornerColor);canvas.drawRect((float) frame.left, (float) frame.top, (float) (frame.left + CORNER_RECT_WIDTH), (float) (frame.top + CORNER_RECT_HEIGHT), this.paint);canvas.drawRect((float) frame.left, (float) frame.top, (float) (frame.left + CORNER_RECT_HEIGHT), (float) (frame.top + CORNER_RECT_WIDTH), this.paint);canvas.drawRect((float) (frame.right - 8), (float) frame.top, (float) frame.right, (float) (frame.top + CORNER_RECT_HEIGHT), this.paint);canvas.drawRect((float) (frame.right - 40), (float) frame.top, (float) frame.right, (float) (frame.top + CORNER_RECT_WIDTH), this.paint);canvas.drawRect((float) frame.left, (float) (frame.bottom - 8), (float) (frame.left + CORNER_RECT_HEIGHT), (float) frame.bottom, this.paint);canvas.drawRect((float) frame.left, (float) (frame.bottom - 40), (float) (frame.left + CORNER_RECT_WIDTH), (float) frame.bottom, this.paint);canvas.drawRect((float) (frame.right - 8), (float) (frame.bottom - 40), (float) frame.right, (float) frame.bottom, this.paint);canvas.drawRect((float) (frame.right - 40), (float) (frame.bottom - 8), (float) frame.right, (float) frame.bottom, this.paint);}private void drawLaserScanner(Canvas canvas, Rect frame) {this.paint.setColor(this.laserColor);LinearGradient linearGradient = new LinearGradient((float) frame.left, (float) scannerStart, (float) frame.left, (float) (scannerStart + 10), shadeColor(this.laserColor), this.laserColor, TileMode.MIRROR);RadialGradient radialGradient = new RadialGradient((float) (frame.left + (frame.width() / 2)), (float) (scannerStart + 5), 360.0f, this.laserColor, shadeColor(this.laserColor), TileMode.MIRROR);SweepGradient sweepGradient = new SweepGradient((float) (frame.left + (frame.width() / 2)), (float) (scannerStart + 10), shadeColor(this.laserColor), this.laserColor);ComposeShader composeShader = new ComposeShader(radialGradient, linearGradient, Mode.ADD);this.paint.setShader(radialGradient);if (scannerStart <= scannerEnd) {canvas.drawOval(new RectF((float) (frame.left + 20), (float) scannerStart, (float) (frame.right - 20), (float) (scannerStart + 10)), this.paint);scannerStart += 5;} else {scannerStart = frame.top;}this.paint.setShader(null);}public int shadeColor(int color) {return Integer.valueOf("20" + Integer.toHexString(color).substring(2), 16).intValue();}private void drawFrame(Canvas canvas, Rect frame) {this.paint.setColor(this.frameColor);canvas.drawRect((float) frame.left, (float) frame.top, (float) (frame.right + 1), (float) (frame.top + 2), this.paint);canvas.drawRect((float) frame.left, (float) (frame.top + 2), (float) (frame.left + 2), (float) (frame.bottom - 1), this.paint);canvas.drawRect((float) (frame.right - 1), (float) frame.top, (float) (frame.right + 1), (float) (frame.bottom - 1), this.paint);canvas.drawRect((float) frame.left, (float) (frame.bottom - 1), (float) (frame.right + 1), (float) (frame.bottom + 1), this.paint);}private void drawExterior(Canvas canvas, Rect frame, int width, int height) {this.paint.setColor(this.resultBitmap != null ? this.resultColor : this.maskColor);canvas.drawRect(0.0f, 0.0f, (float) width, (float) frame.top, this.paint);canvas.drawRect(0.0f, (float) frame.top, (float) frame.left, (float) (frame.bottom + 1), this.paint);canvas.drawRect((float) (frame.right + 1), (float) frame.top, (float) width, (float) (frame.bottom + 1), this.paint);canvas.drawRect(0.0f, (float) (frame.bottom + 1), (float) width, (float) height, this.paint);}public void drawViewfinder() {this.resultBitmap = null;invalidate();}public void drawResultBitmap(Bitmap barcode) {this.resultBitmap = barcode;invalidate();}public void addPossibleResultPoint(ResultPoint point) {this.possibleResultPoints.add(point);}public void setLabelText(String labelText) {this.labelText = labelText;}public void setLabelTextColor(int labelTextColor) {this.labelTextColor = labelTextColor;}public void setLabelTextSize(float labelTextSize) {this.labelTextSize = labelTextSize;}
}
FileUtil.java
public class FileUtil {private static String TAG = "FileUtil";public static String randomFileName(String ext) {return Long.toString(System.currentTimeMillis()) + ext;}public static boolean deleteFile(String name) {File file = new File(name);if (file.exists()) {return file.delete();}return false;}@SuppressWarnings("deprecation")public static String rotateAndSaveBitmap(File file, int outW, int outH, String outPath, Bitmap.CompressFormat format, int quality) {int originW;int originH;int orientation = ExifInterface.ORIENTATION_NORMAL;try {ExifInterface exif = new ExifInterface(file.getAbsolutePath());orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);int w = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0);int h = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0);switch (orientation) {case ExifInterface.ORIENTATION_UNDEFINED:return null;case ExifInterface.ORIENTATION_ROTATE_90:case ExifInterface.ORIENTATION_ROTATE_270:originW = h;originH = w;break;default:originW = w;originH = h;break;}} catch (Exception e) {return null;}// boost decode bitmap performanceint sampleSize;if (outW <= 0 && outH <= 0) {sampleSize = 1;outW = originW;outH = originH;} else if (outW <= 0 || outH <= 0) {if (outW <= 0) {sampleSize = originH / outH;outW = (int) (originW * (outH / (float) originH));} else {sampleSize = originW / outW;outH = (int) (originH * (outW / (float) originW));}} else {sampleSize = Math.min(originW / outW, originH / outH);}BitmapFactory.Options bmOptions = new BitmapFactory.Options();bmOptions.inJustDecodeBounds = false;bmOptions.inSampleSize = sampleSize;bmOptions.inPurgeable = true;Bitmap bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), bmOptions);float scaleX = outW;float scaleY = outH;Matrix matrix = new Matrix();switch (orientation) {case ExifInterface.ORIENTATION_NORMAL:scaleX /= bmp.getWidth();scaleY /= bmp.getHeight();matrix.postScale(scaleX, scaleY);break;case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:scaleX /= bmp.getWidth();scaleY /= bmp.getHeight();matrix.setScale(-1, 1);matrix.postScale(scaleX, scaleY);break;case ExifInterface.ORIENTATION_ROTATE_180:scaleX /= bmp.getWidth();scaleY /= bmp.getHeight();matrix.setRotate(180);matrix.postScale(scaleX, scaleY);break;case ExifInterface.ORIENTATION_FLIP_VERTICAL:scaleX /= bmp.getWidth();scaleY /= bmp.getHeight();matrix.setRotate(180);matrix.postScale(-1, 1);matrix.postScale(scaleX, scaleY);break;case ExifInterface.ORIENTATION_TRANSPOSE:scaleX /= bmp.getWidth();scaleY /= bmp.getHeight();matrix.setRotate(90);matrix.postScale(-1, 1);matrix.postScale(scaleX, scaleY);break;case ExifInterface.ORIENTATION_ROTATE_90:scaleX /= bmp.getHeight();scaleY /= bmp.getWidth();matrix.setRotate(90);matrix.postScale(scaleX, scaleY);break;case ExifInterface.ORIENTATION_TRANSVERSE:scaleX /= bmp.getWidth();scaleY /= bmp.getHeight();matrix.setRotate(-90);matrix.postScale(-1, 1);matrix.postScale(scaleX, scaleY);break;case ExifInterface.ORIENTATION_ROTATE_270:scaleX /= bmp.getHeight();scaleY /= bmp.getWidth();matrix.setRotate(-90);matrix.postScale(scaleX, scaleY);break;default:break;}Bitmap bmpNew = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);String newFile = bmp2File(bmpNew, outPath, format, quality);bmpNew.recycle();return newFile;}private static Point getBitmapSize(String file) {BitmapFactory.Options bmOptions = new BitmapFactory.Options();bmOptions.inJustDecodeBounds = true;BitmapFactory.decodeFile(file, bmOptions);int originW = bmOptions.outWidth;int originH = bmOptions.outHeight;return new Point(originW, originH);}@SuppressWarnings("deprecation")public static String saveBitmap(File f, int outW, int outH, String outPath, Bitmap.CompressFormat format, int quality) {String rotateFile = rotateAndSaveBitmap(f, outW, outH, outPath, format, quality);if (null != rotateFile)return rotateFile;if (f == null) return "";String file = f.getAbsolutePath();// Get the dimensions of the bitmapPoint size = getBitmapSize(file);int originW = size.x;int originH = size.y;// Determine how much to scale down the imageint scaleFactor;if (outW <= 0 && outH <= 0) {scaleFactor = 1;outW = originW;outH = originH;} else if (outW <= 0 || outH <= 0) {if (outW <= 0) {scaleFactor = originH / outH;outW = (int) (originW * (outH / (float) originH));} else {scaleFactor = originW / outW;outH = (int) (originH * (outW / (float) originW));}} else {scaleFactor = Math.min(originW / outW, originH / outH);}// Decode the image file into a Bitmap sized to fit out sizeBitmapFactory.Options bmOptions = new BitmapFactory.Options();bmOptions.inJustDecodeBounds = false;bmOptions.inSampleSize = scaleFactor;bmOptions.inPurgeable = true;Bitmap bmp = BitmapFactory.decodeFile(file, bmOptions);String newFile;if (bmp == null) {return "";}if (bmp.getWidth() != outW && bmp.getHeight() != outH) {Bitmap bmpNew = Bitmap.createScaledBitmap(bmp, outW, outH, true);newFile = bmp2File(bmpNew, outPath, format, quality);bmpNew.recycle();} else {newFile = bmp2File(bmp, outPath, format, quality);}bmp.recycle();return newFile;}public static Point calcScaleSize(String file, int outW, int outH) {int originW = 0;int originH = 0;try {ExifInterface exif = new ExifInterface(file);int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);int w = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0);int h = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0);switch (orientation) {case ExifInterface.ORIENTATION_UNDEFINED:break;case ExifInterface.ORIENTATION_ROTATE_90:case ExifInterface.ORIENTATION_ROTATE_270:originW = h;originH = w;break;default:originW = w;originH = h;break;}} catch (Exception e) {}if (0 == originW || 0 == originH) {Point size = getBitmapSize(file);originW = size.x;originH = size.y;}if (outW <= 0 && outH <= 0) {outW = originW;outH = originH;} else if (outW <= 0 || outH <= 0) {if (outW <= 0) {outW = (int) (originW * (outH / (float) originH));} else {outH = (int) (originH * (outW / (float) originW));}} else {}return new Point(outW, outH);}public static String bmp2File(Bitmap bmp, String filePath, Bitmap.CompressFormat format, int quality) {String fileName = FileUtil.randomFileName(Bitmap.CompressFormat.PNG == format ? ".png" : ".jpg");String fullPath = filePath + fileName;deleteFile(fileName);File file = new File(fullPath);try {file.createNewFile();} catch (IOException e) {e.printStackTrace();return null;}FileOutputStream fOut = null;try {fOut = new FileOutputStream(file);} catch (FileNotFoundException e) {e.printStackTrace();return null;}bmp.compress(format, quality, fOut);try {fOut.flush();fOut.close();fOut = null;} catch (IOException e) {e.printStackTrace();return null;} finally {try {if (null != fOut) {fOut.close();fOut = null;}} catch (Exception e) {e.printStackTrace();return null;}}return fileName;}public static final String insertImage(ContentResolver cr, String imagePath, String name, String description) throws FileNotFoundException {FileInputStream inStream = new FileInputStream(imagePath);return insertImage(cr, inStream, name, description);}/*** A copy of the Android internals insertImage method, this method populates* the meta data with DATE_ADDED and DATE_TAKEN. This fixes a common problem* where media that is inserted manually gets saved at the end of the* gallery (because date is not populated).** @see Images.Media#insertImage(ContentResolver,* Bitmap, String, String)*/public static final String insertImage(ContentResolver cr, FileInputStream inStream, String title, String description) {ContentValues values = new ContentValues();values.put(Images.Media.TITLE, title);values.put(Images.Media.DISPLAY_NAME, title);values.put(Images.Media.DESCRIPTION, description);values.put(Images.Media.MIME_TYPE, "image/jpeg");// Add the date meta data to ensure the image is added at the front of// the galleryvalues.put(Images.Media.DATE_ADDED, System.currentTimeMillis());values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis());Uri url = null;String stringUrl = null; /* value to be returned */try {url = cr.insert(Images.Media.EXTERNAL_CONTENT_URI, values);if (inStream != null) {OutputStream imageOut = cr.openOutputStream(url);byte[] buffer = new byte[1024];int count = 0;while ((count = inStream.read(buffer)) >= 0) {imageOut.write(buffer, 0, count);}imageOut.flush();inStream.close();long id = ContentUris.parseId(url);// Wait until MINI_KIND thumbnail is generated.Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id, Images.Thumbnails.MINI_KIND, null);// This is for backward compatibility.storeThumbnail(cr, miniThumb, id, 50F, 50F, Images.Thumbnails.MICRO_KIND);} else {cr.delete(url, null, null);url = null;}} catch (Exception e) {e.printStackTrace();if (url != null) {cr.delete(url, null, null);url = null;}}if (url != null) {stringUrl = url.toString();}return stringUrl;}/*** A copy of the Android internals StoreThumbnail method, it used with the* insertImage to populate the* android.provider.MediaStore.Images.Media#insertImage with all the correct* meta data. The StoreThumbnail method is private so it must be duplicated* here.** @see Images.Media (StoreThumbnail private* method)*/private static final Bitmap storeThumbnail(ContentResolver cr, Bitmap source, long id, float width, float height, int kind) {// create the matrix to scale itMatrix matrix = new Matrix();float scaleX = width / source.getWidth();float scaleY = height / source.getHeight();matrix.setScale(scaleX, scaleY);Bitmap thumb = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);ContentValues values = new ContentValues(4);values.put(Images.Thumbnails.KIND, kind);values.put(Images.Thumbnails.IMAGE_ID, (int) id);values.put(Images.Thumbnails.HEIGHT, thumb.getHeight());values.put(Images.Thumbnails.WIDTH, thumb.getWidth());Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values);try {OutputStream thumbOut = cr.openOutputStream(url);thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);thumbOut.close();return thumb;} catch (FileNotFoundException ex) {return null;} catch (IOException ex) {return null;}}// /@SuppressLint("NewApi")public static String checkPicturePath(final Context context, final Uri uri) {final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;// DocumentProviderif (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {// ExternalStorageProviderif (isExternalStorageDocument(uri)) {final String docId = DocumentsContract.getDocumentId(uri);final String[] split = docId.split(":");final String type = split[0];if ("primary".equalsIgnoreCase(type)) {return Environment.getExternalStorageDirectory() + "/" + split[1];}}// DownloadsProviderelse if (isDownloadsDocument(uri)) {final String id = DocumentsContract.getDocumentId(uri);final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));return getDataColumn(context, contentUri, null, null);}// MediaProviderelse if (isMediaDocument(uri)) {final String docId = DocumentsContract.getDocumentId(uri);final String[] split = docId.split(":");final String type = split[0];Uri contentUri = null;if ("image".equals(type)) {contentUri = Images.Media.EXTERNAL_CONTENT_URI;} else if ("video".equals(type)) {contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;} else if ("audio".equals(type)) {contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;}final String selection = "_id=?";final String[] selectionArgs = new String[]{split[1]};return getDataColumn(context, contentUri, selection, selectionArgs);}}// MediaStore (and general)else if ("content".equalsIgnoreCase(uri.getScheme())) {// Return the remote addressif (isGooglePhotosUri(uri))return uri.getLastPathSegment();return getDataColumn(context, uri, null, null);}// Fileelse if ("file".equalsIgnoreCase(uri.getScheme())) {return uri.getPath();}return null;}/*** Get the value of the data column for this Uri. This is useful for* MediaStore Uris, and other file-based ContentProviders.** @param context       The context.* @param uri           The Uri to query.* @param selection     (Optional) Filter used in the query.* @param selectionArgs (Optional) Selection arguments used in the query.* @return The value of the _data column, which is typically a file path.*/private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {Cursor cursor = null;final String column = "_data";final String[] projection = {column};try {cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);if (cursor != null && cursor.moveToFirst()) {final int index = cursor.getColumnIndexOrThrow(column);return cursor.getString(index);}} catch (Exception e) {e.printStackTrace();} finally {if (cursor != null)cursor.close();}return null;}/*** @param uri The Uri to check.* @return Whether the Uri authority is ExternalStorageProvider.*/private static boolean isExternalStorageDocument(Uri uri) {return "com.android.externalstorage.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is DownloadsProvider.*/private static boolean isDownloadsDocument(Uri uri) {return "com.android.providers.downloads.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is MediaProvider.*/private static boolean isMediaDocument(Uri uri) {return "com.android.providers.media.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is Google Photos.*/private static boolean isGooglePhotosUri(Uri uri) {return "com.google.android.apps.photos.content".equals(uri.getAuthority());}
}
IMResUtil.java
public class IMResUtil {private static final String TAG = "IMResUtil";private static IMResUtil instance;private        Context   context;private static Class id = null;private static Class layout = null;private static Class style = null;private static Class attr = null;private static Class styleable = null;public IMResUtil(Context paramContext) {this.context = paramContext.getApplicationContext();try {layout = Class.forName(this.context.getPackageName() + ".R$layout");} catch (ClassNotFoundException localClassNotFoundException2) {Log.e(TAG,"localClassNotFoundException2 = " + localClassNotFoundException2.toString());}try {id = Class.forName(this.context.getPackageName() + ".R$id");} catch (ClassNotFoundException localClassNotFoundException3) {Log.e(TAG,"localClassNotFoundException3 = " + localClassNotFoundException3.toString());}try {style = Class.forName(this.context.getPackageName() + ".R$style");} catch (ClassNotFoundException localClassNotFoundException5) {Log.e(TAG,"localClassNotFoundException5 = " + localClassNotFoundException5.toString());}try {attr = Class.forName(this.context.getPackageName() + ".R$attr");} catch (ClassNotFoundException localClassNotFoundException10) {Log.e(TAG,"localClassNotFoundException10 = " + localClassNotFoundException10.toString());}try {styleable = Class.forName(this.context.getPackageName() + ".R$styleable");} catch (ClassNotFoundException localClassNotFoundException10) {Log.e(TAG,"localClassNotFoundException10 = " + localClassNotFoundException10.toString());}}public static IMResUtil getResofR(Context paramContext) {if (instance == null)instance = new IMResUtil(paramContext);return instance;}public int getId(String paramString) {return getResofR(id, paramString);}public  int getLayout(String paramString) {return getResofR(layout, paramString);}public int getStyle(String paramString) {return getResofR(style, paramString);}public  int getAttr(String paramString) {return getResofR(attr, paramString);}public  int getStyleable(String paramString) {return getResofR(styleable, paramString);}public int [] getStyleableArray(String paramString){try {Class clz = Class.forName(context.getPackageName()+".R$styleable");Field field = clz.getField(paramString);Object object = field.get(clz);int[] attr = (int[]) object;for (int i = 0; i < attr.length; i++) {Log.d(TAG, attr[i]+"");}return attr;} catch (Exception e) {Log.d(TAG, e.getMessage());e.printStackTrace();}return null;}private  int getResofR(Class<?> paramClass, String paramString) {if (paramClass == null) {Log.d(TAG,"getRes(null," + paramString + ")");Log.d(TAG,"Class is null ,ResClass is not initialized.");return -1;
//            throw new IllegalArgumentException("ResClass is not initialized.");}try {Field localField = paramClass.getField(paramString);int k = localField.getInt(paramString);return k;} catch (Exception localException) {Log.e(TAG,"getRes(" + paramClass.getName() + ", " + paramString + ")");Log.e(TAG,"Error getting resource. Make sure you have copied all resources (res/) from SDK to your project. ");Log.e(TAG,localException.getMessage());}return -1;}
}

xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><!--抬头部分--><RelativeLayoutandroid:id="@+id/rl"android:layout_width="fill_parent"android:layout_height="50dp"android:background="#000000"android:paddingLeft="6dp"android:paddingStart="6dp"><ImageViewandroid:id="@+id/iv_qr_back"android:layout_width="30dp"android:layout_height="24dp"android:layout_centerVertical="true"android:src="@drawable/arrow_back"/><TextViewandroid:id="@+id/tv_qr_title"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_centerHorizontal="true"android:clickable="true"android:focusable="true"android:gravity="center"android:textColor="#ffffff"android:textSize="20sp"/><TextViewandroid:id="@+id/tv_qr_open_image"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_alignParentEnd="true"android:layout_alignParentRight="true"android:layout_marginEnd="15dp"android:layout_marginRight="15dp"android:clickable="true"android:focusable="true"android:gravity="center"android:textColor="#ffffff"android:textSize="20sp"/></RelativeLayout><!--主体部分--><SurfaceViewandroid:id="@+id/device_qrcode_preview_view"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_below="@+id/rl"/><com.yzq.zxinglibrary.view.ViewfinderViewandroid:id="@+id/vv_qr_viewfinderView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"app:device_qrcode_corner_color="#005699"app:device_qrcode_frame_color="#90FFFFFF"app:device_qrcode_laser_color="#005699"app:device_qrcode_mask_color="#60000000"app:device_qrcode_result_color="#B0000000"app:device_qrcode_result_point_color="#C0FFFF00"/><!--app:label_text="将二维码放入框中,即可扫描"app:label_text_color="#ffffff"app:label_text_size="16sp"--><!--扫描灯光--><LinearLayoutandroid:id="@+id/bottomLayout"android:layout_width="match_parent"android:layout_height="96dp"android:layout_alignParentBottom="true"android:layout_gravity="bottom"android:background="#99000000"android:orientation="horizontal"><LinearLayoutandroid:id="@+id/flashLightLayout"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:orientation="vertical"><!--android:background="@drawable/device_qrcode_scan_flash_off"--><ImageViewandroid:id="@+id/flashLightIv"android:layout_width="36dp"android:layout_height="36dp"android:scaleType="centerCrop"android:tint="#ffffffff"/><TextViewandroid:id="@+id/flashLightTv"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:gravity="center"android:text="打开闪光灯"android:textColor="@color/result_text"/></LinearLayout><LinearLayoutandroid:id="@+id/albumLayout"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:orientation="vertical"><ImageViewandroid:id="@+id/img_phone"android:layout_width="36dp"android:layout_height="36dp"android:scaleType="centerCrop"android:tint="#ffffffff"android:src="@drawable/ic_photo"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:gravity="center"android:text="相册"android:textColor="@color/result_text"/></LinearLayout></LinearLayout></RelativeLayout>

清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.xxx.zxinglibrary"><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.FLASHLIGHT" /><uses-feature android:name="android.hardware.camera" /><uses-feature android:name="android.hardware.camera.autofocus" /><uses-permission android:name="android.permission.VIBRATE" /><uses-permission android:name="android.permission.WAKE_LOCK" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><application><activityandroid:name=".decode.CaptureActivity"android:configChanges="orientation|screenSize"android:screenOrientation="portrait"android:theme="@android:style/Theme.NoTitleBar"android:windowSoftInputMode="adjustPan|stateHidden" /></application></manifest>

以上的总结如果能够帮助到你,希望给个赞,如果不能,或者有更好的推荐,不管是拍砖,还是怎样,烦请留言,提供链接,改动方案,或者提供更好的优化建议,谢谢!我们定会虚心采纳,谢谢!

Android 基于Zxing的二维码扫描优化相关推荐

  1. 修正Android基于ZXing的二维码扫描——横竖屏自由切换

    概述: 此博客是基于开源的框架ZXing.ZXing用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口.ZXing可以实现使用手机的内置的摄像头完成条形码的扫描及解码.该 ...

  2. 基于zxing的二维码扫描

    前言 现在的应用中二维码扫描已经成为一个应用必不可少的功能,现在大部分Android二维码扫描都是基于zxing和Zbar,这文章就来介绍一下基于zxing的二维码扫描.先看下效果图 虽然现在的关于二 ...

  3. 基于zxing的二维码扫描(软件界面)

    原文地址:https://www.jianshu.com/p/ee2ee7677831 前言 现在的应用中二维码扫描已经成为一个应用必不可少的功能,现在大部分Android二维码扫描都是基于zxing ...

  4. Android实战——Zxing实现二维码扫描

    Zxing实现二维码扫描 前言: 本篇文章从初学者的角度出发,从一个不知道对二维码扫描怎么下手的工作者,需要一个简单的扫描功能的话,可以阅读该篇文章.作为Google开源框架Zxing,里面的文件很大 ...

  5. (转载)Android项目实战(二十八):使用Zxing实现二维码及优化实例

    Android项目实战(二十八):使用Zxing实现二维码及优化实例 作者:听着music睡 字体:[增加 减小] 类型:转载 时间:2016-11-21 我要评论 这篇文章主要介绍了Android项 ...

  6. JAVA实现基于ZXing的二维码自动生成与图片合成

    JAVA实现基于ZXing的二维码自动生成与图片合成 近日做项目需要生成带有信息的二维码,并嵌入到一张图片中.实现思路采用Zxing生成二维码,java图形库进行图片的嵌入. 生成二维码 ZXing是 ...

  7. 基于zxing生成二维码

    目录 1.二维码的原理 2.基于zxing生成二维码 3.逻辑及其应用 完整代码:https://github.com/122537067/zxingQRcodeLogoColor 效果图: 1.二维 ...

  8. 二维码扫描优化及爱奇艺App的实践

    写在前面 二维码是一个近几年来移动设备上超流行的一种编码方式(又称二维条码,QR Code,QR全称QuickResponse),它比传统的条形码(Bar Code)能存更多的信息,也能表示更多的数据 ...

  9. Android:实际运用Zxing集成二维码扫描 及 自定义扫码界面(demo源码)

    二维码扫描,各大主流App必不可少的功能,而且google已将轮子替我们造好,直接拿来使用即可.以下是教学如何将Zxing开源库集成到自己项目中,并且自定义扫码界面,后期可根据自己的业务需求进行修改, ...

最新文章

  1. Codeforces Round #353 (Div. 2)
  2. C# 实现将 PDF 转文本的功能
  3. Silverlight+WCF 新手实例 象棋 WCF通讯跨域(十五)
  4. pagerank数据集_从数据结构到算法:图网络方法初探
  5. Animate.css介绍
  6. 数据库(三),底层算法
  7. 程序员亲身体验的学历之痛
  8. sqlsever 查询最新时间
  9. ACDSee Photo Studio 7 Mac(数字图像处理软件)
  10. [渝粤教育] 天津师范大学 教育心理学(唐卫海) 参考 资料
  11. Java利用递归算法实现24点游戏
  12. 使用frp进行内网穿透
  13. 线上线下协同发展,020 商业解析
  14. iOS 支付宝支付 微信支付SDK接口不统一? 盘他!
  15. html的css怎么设置深度,vue css 深度选择器
  16. poj 1729 Jack and Jill 1376 Robot 1324 Holedox Moving 1475 Pushing Boxes bfs + a*
  17. es6 取数组的第一个和最后一个_es6常用数组操作及技巧汇总
  18. Windows向Linux自动传输文件,Windows向虚拟机Linux传输文件方法
  19. android控制电路板的开关灯,一文解读LED触摸调光台灯控制电路板的工作原理
  20. 仓库 store getter

热门文章

  1. 【区块链 | ENS】ENS中的Namehash加密逻辑
  2. 2015 中国大数据技术大会 PPT 尝鲜
  3. 你被美国监控了,美国监控丑闻——棱镜项目事件
  4. 条件编译/条件宏定义
  5. BCGControlBarPro CBCGPGridCtrl单元格添加控件
  6. 单片机接收到红外对管的数据怎么用c语言程序传给led显示器,单片机实现遥控器-红外数据传输--红外编解码原理...
  7. 安徽三连学院计算机考试,安徽三联学院2017年3月计算机等级考试报名时间
  8. 联想ThinkPad E40安装XP的方法
  9. Android Support Library 学习入门
  10. Unity 之 UGUI Layout自动布局组件详解