久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Android 基于Zxing的二維碼掃描優(yōu)化

 卡瑞吉 2020-04-16

最近公司項(xiàng)目App中要集成二維碼掃描來適應(yīng)在戶外工作的時(shí)候,對(duì)碼頭集裝箱等上面貼的A4紙張打印的二維碼進(jìn)行識(shí)別, 一般App二維碼集成后,能掃出來就不管了,但是我們?cè)诩沙晒?根據(jù)用戶反饋,在戶外的環(huán)境下,很多二維碼識(shí)別不了,或者識(shí)別速度慢,我們自己也是適用了一下,發(fā)現(xiàn)也確實(shí)是這樣.

  一般造成這個(gè)識(shí)別不出來的原因,我們總結(jié)了以下幾點(diǎn):

  1. A4紙張打印的標(biāo)簽二維碼, 本來打印就不是特別清晰,有些像素點(diǎn),不一定都打印了出來,

  2. 戶外環(huán)境,多變,灰塵,粉塵影響

  3. 日曬雨淋,還有各種劃痕,造成了二維碼破損和有污漬

  4. Android手機(jī)配置不一樣,有的手機(jī)好一點(diǎn),像素高,有的用戶的像素低

大概就是這些,但是用基于QBar(在Zxing上做了優(yōu)化)的微信,卻能很快的識(shí)別出上面幾種情況造成的二維碼; 基于libqrencode 庫集成的支付寶或者釘釘二維碼掃描,一樣也能識(shí)別出來;還有IOS也就是調(diào)用系統(tǒng)的掃描,也一樣能夠掃描出來,為啥我們大android不行?

老板不管這些,只是說了,別人的可以,為啥你的不可以,那就是你的問題.......

網(wǎng)上找了很多各種幾千個(gè)贊的第三方集成的二維碼,根本就不能滿足上面的需求,當(dāng)時(shí)感覺真心不知道怎么辦好了.

  唯獨(dú)網(wǎng)上找的這個(gè)還可以一點(diǎn):https://github.com/vondear/RxTool 但是破損一些的還是掃描不出來;那個(gè)網(wǎng)上幾千個(gè)贊的一片楓葉的 ,這種環(huán)境下的二維碼掃描根本邊都摸不到.

  還有郭林推薦的:https://github.com/al4fun/SimpleScanner 這個(gè)庫,雖然是大神推薦的,但是比上面的這個(gè),還要差那么好幾點(diǎn),郭林的推薦的二維碼掃描鏈接:https://mp.weixin.qq.com/s/aPqSK1FlsPiENzSE48BVUA

 沒辦法,最后只能自己動(dòng)手,網(wǎng)上找的,沒有找到合適的,目前我們修改的二維碼掃描基本可以做到:除了破損的識(shí)別不了,其他的都能識(shí)別,就是有時(shí)候速度慢了點(diǎn),要多對(duì)一下焦,勉強(qiáng)能夠比上面好那么一點(diǎn)點(diǎn)而已.

代碼如下: (這里面很多類都在原有類的基礎(chǔ)上有改動(dòng),雖然類名相同,但是里面的方法有些有變動(dòng)!)

build.gradle

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

文件目錄如下:

ZxingConfig.java
  1. public class ZxingConfig implements Serializable {
  2. /*是否播放聲音*/
  3. private boolean isPlayBeep = true;
  4. /*是否震動(dòng)*/
  5. private boolean isShake = false;
  6. /*是否顯示下方的其他功能布局*/
  7. private boolean isShowbottomLayout = true;
  8. /*是否顯示閃光燈按鈕*/
  9. private boolean isShowFlashLight = true;
  10. /*是否顯示相冊(cè)按鈕*/
  11. private boolean isShowAlbum = true;
  12. public boolean isPlayBeep() {
  13. return isPlayBeep;
  14. }
  15. public void setPlayBeep(boolean playBeep) {
  16. isPlayBeep = playBeep;
  17. }
  18. public boolean isShake() {
  19. return isShake;
  20. }
  21. public void setShake(boolean shake) {
  22. isShake = shake;
  23. }
  24. public boolean isShowbottomLayout() {
  25. return isShowbottomLayout;
  26. }
  27. public void setShowbottomLayout(boolean showbottomLayout) {
  28. isShowbottomLayout = showbottomLayout;
  29. }
  30. public boolean isShowFlashLight() {
  31. return isShowFlashLight;
  32. }
  33. public void setShowFlashLight(boolean showFlashLight) {
  34. isShowFlashLight = showFlashLight;
  35. }
  36. public boolean isShowAlbum() {
  37. return isShowAlbum;
  38. }
  39. public void setShowAlbum(boolean showAlbum) {
  40. isShowAlbum = showAlbum;
  41. }
  42. }
CameraFacing.java
  1. public enum CameraFacing {
  2. BACK, // must be value 0!
  3. FRONT, // must be value 1!
  4. }
OpenCamera.java
  1. public final class OpenCamera {
  2. private final int index;
  3. private final Camera camera;
  4. private final CameraFacing facing;
  5. private final int orientation;
  6. public OpenCamera(int index, Camera camera, CameraFacing facing, int orientation) {
  7. this.index = index;
  8. this.camera = camera;
  9. this.facing = facing;
  10. this.orientation = orientation;
  11. }
  12. public Camera getCamera() {
  13. return camera;
  14. }
  15. public CameraFacing getFacing() {
  16. return facing;
  17. }
  18. public int getOrientation() {
  19. return orientation;
  20. }
  21. @Override
  22. public String toString() {
  23. return "Camera #" + index + " : " + facing + ',' + orientation;
  24. }
  25. }
OpenCameraInterface.java
  1. public final class OpenCameraInterface {
  2. private static final String TAG = OpenCameraInterface.class.getName();
  3. private OpenCameraInterface() {
  4. }
  5. /**
  6. * For {@link #open(int)}, means no preference for which camera to open.
  7. */
  8. public static final int NO_REQUESTED_CAMERA = -1;
  9. /**
  10. * Opens the requested camera with {@link Camera#open(int)}, if one exists.
  11. *
  12. * @param cameraId camera ID of the camera to use. A negative value
  13. * or {@link #NO_REQUESTED_CAMERA} means "no preference", in which case a rear-facing
  14. * camera is returned if possible or else any camera
  15. * @return handle to {@link OpenCamera} that was opened
  16. */
  17. public static OpenCamera open(int cameraId) {
  18. int numCameras = Camera.getNumberOfCameras();
  19. if (numCameras == 0) {
  20. Log.w(TAG, "No cameras!");
  21. return null;
  22. }
  23. boolean explicitRequest = cameraId >= 0;
  24. Camera.CameraInfo selectedCameraInfo = null;
  25. int index;
  26. if (explicitRequest) {
  27. index = cameraId;
  28. selectedCameraInfo = new Camera.CameraInfo();
  29. Camera.getCameraInfo(index, selectedCameraInfo);
  30. } else {
  31. index = 0;
  32. while (index < numCameras) {
  33. Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
  34. Camera.getCameraInfo(index, cameraInfo);
  35. CameraFacing reportedFacing = CameraFacing.values()[cameraInfo.facing];
  36. if (reportedFacing == CameraFacing.BACK) {
  37. selectedCameraInfo = cameraInfo;
  38. break;
  39. }
  40. index++;
  41. }
  42. }
  43. Camera camera;
  44. if (index < numCameras) {
  45. Log.i(TAG, "Opening camera #" + index);
  46. camera = Camera.open(index);
  47. } else {
  48. if (explicitRequest) {
  49. Log.w(TAG, "Requested camera does not exist: " + cameraId);
  50. camera = null;
  51. } else {
  52. Log.i(TAG, "No camera facing " + CameraFacing.BACK + "; returning camera #0");
  53. camera = Camera.open(0);
  54. selectedCameraInfo = new Camera.CameraInfo();
  55. Camera.getCameraInfo(0, selectedCameraInfo);
  56. }
  57. }
  58. if (camera == null) {
  59. return null;
  60. }
  61. return new OpenCamera(index,
  62. camera,
  63. CameraFacing.values()[selectedCameraInfo.facing],
  64. selectedCameraInfo.orientation);
  65. }
  66. }
AutoFocusManager.java
  1. final class AutoFocusManager implements Camera.AutoFocusCallback {
  2. private static final String TAG = AutoFocusManager.class.getSimpleName();
  3. private static final long AUTO_FOCUS_INTERVAL_MS = 2000L;
  4. private static final Collection<String> FOCUS_MODES_CALLING_AF;
  5. static {
  6. FOCUS_MODES_CALLING_AF = new ArrayList<>(2);
  7. FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO);
  8. FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO);
  9. }
  10. private boolean stopped;
  11. private boolean focusing;
  12. private final boolean useAutoFocus;
  13. private final Camera camera;
  14. private AsyncTask<?,?,?> outstandingTask;
  15. AutoFocusManager(Context context, Camera camera) {
  16. this.camera = camera;
  17. SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
  18. String currentFocusMode = camera.getParameters().getFocusMode();
  19. useAutoFocus =
  20. sharedPrefs.getBoolean(QRConstants.KEY_AUTO_FOCUS, true) &&
  21. FOCUS_MODES_CALLING_AF.contains(currentFocusMode);
  22. Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus);
  23. start();
  24. }
  25. @Override
  26. public synchronized void onAutoFocus(boolean success, Camera theCamera) {
  27. focusing = false;
  28. autoFocusAgainLater();
  29. }
  30. private synchronized void autoFocusAgainLater() {
  31. if (!stopped && outstandingTask == null) {
  32. AutoFocusTask newTask = new AutoFocusTask();
  33. try {
  34. newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  35. outstandingTask = newTask;
  36. } catch (RejectedExecutionException ree) {
  37. Log.w(TAG, "Could not request auto focus", ree);
  38. }
  39. }
  40. }
  41. synchronized void start() {
  42. // if (useAutoFocus) {
  43. outstandingTask = null;
  44. if (!stopped && !focusing) {
  45. try {
  46. camera.autoFocus(this);
  47. focusing = true;
  48. } catch (RuntimeException re) {
  49. // Have heard RuntimeException reported in Android 4.0.x+; continue?
  50. Log.w(TAG, "Unexpected exception while focusing", re);
  51. // Try again later to keep cycle going
  52. autoFocusAgainLater();
  53. }
  54. }
  55. // }
  56. }
  57. private synchronized void cancelOutstandingTask() {
  58. if (outstandingTask != null) {
  59. if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) {
  60. outstandingTask.cancel(true);
  61. }
  62. outstandingTask = null;
  63. }
  64. }
  65. synchronized void stop() {
  66. stopped = true;
  67. // if (useAutoFocus) {
  68. cancelOutstandingTask();
  69. // Doesn't hurt to call this even if not focusing
  70. try {
  71. camera.cancelAutoFocus();
  72. } catch (RuntimeException re) {
  73. // Have heard RuntimeException reported in Android 4.0.x+; continue?
  74. Log.w(TAG, "Unexpected exception while cancelling focusing", re);
  75. }
  76. // }
  77. }
  78. private final class AutoFocusTask extends AsyncTask<Object,Object,Object> {
  79. @Override
  80. protected Object doInBackground(Object... voids) {
  81. try {
  82. Thread.sleep(AUTO_FOCUS_INTERVAL_MS);
  83. } catch (InterruptedException e) {
  84. // continue
  85. }
  86. start();
  87. return null;
  88. }
  89. }
  90. }
CameraConfigurationManager.java
  1. final class CameraConfigurationManager {
  2. private static final String TAG = "CameraConfiguration";
  3. private final Context context;
  4. private int cwNeededRotation;
  5. private int cwRotationFromDisplayToCamera;
  6. private Point screenResolution;
  7. private Point cameraResolution;
  8. private Point bestPreviewSize;
  9. private Point previewSizeOnScreen;
  10. CameraConfigurationManager(Context context) {
  11. this.context = context;
  12. }
  13. /**
  14. * Reads, one time, values from the camera that are needed by the app.
  15. */
  16. void initFromCameraParameters(OpenCamera camera) {
  17. Camera.Parameters parameters = camera.getCamera().getParameters();
  18. WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  19. Display display = manager.getDefaultDisplay();
  20. int displayRotation = display.getRotation();
  21. int cwRotationFromNaturalToDisplay;
  22. switch (displayRotation) {
  23. case Surface.ROTATION_0:
  24. cwRotationFromNaturalToDisplay = 0;
  25. break;
  26. case Surface.ROTATION_90:
  27. cwRotationFromNaturalToDisplay = 90;
  28. break;
  29. case Surface.ROTATION_180:
  30. cwRotationFromNaturalToDisplay = 180;
  31. break;
  32. case Surface.ROTATION_270:
  33. cwRotationFromNaturalToDisplay = 270;
  34. break;
  35. default:
  36. // Have seen this return incorrect values like -90
  37. if (displayRotation % 90 == 0) {
  38. cwRotationFromNaturalToDisplay = (360 + displayRotation) % 360;
  39. } else {
  40. throw new IllegalArgumentException("Bad rotation: " + displayRotation);
  41. }
  42. }
  43. Log.i(TAG, "Display at: " + cwRotationFromNaturalToDisplay);
  44. int cwRotationFromNaturalToCamera = camera.getOrientation();
  45. Log.i(TAG, "Camera at: " + cwRotationFromNaturalToCamera);
  46. // Still not 100% sure about this. But acts like we need to flip this:
  47. if (camera.getFacing() == CameraFacing.FRONT) {
  48. cwRotationFromNaturalToCamera = (360 - cwRotationFromNaturalToCamera) % 360;
  49. Log.i(TAG, "Front camera overriden to: " + cwRotationFromNaturalToCamera);
  50. }
  51. /*
  52. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
  53. String overrideRotationString;
  54. if (camera.getFacing() == CameraFacing.FRONT) {
  55. overrideRotationString = prefs.getString(PreferencesActivity.KEY_FORCE_CAMERA_ORIENTATION_FRONT, null);
  56. } else {
  57. overrideRotationString = prefs.getString(PreferencesActivity.KEY_FORCE_CAMERA_ORIENTATION, null);
  58. }
  59. if (overrideRotationString != null && !"-".equals(overrideRotationString)) {
  60. Log.i(TAG, "Overriding camera manually to " + overrideRotationString);
  61. cwRotationFromNaturalToCamera = Integer.parseInt(overrideRotationString);
  62. }
  63. */
  64. cwRotationFromDisplayToCamera =
  65. (360 + cwRotationFromNaturalToCamera - cwRotationFromNaturalToDisplay) % 360;
  66. Log.i(TAG, "Final display orientation: " + cwRotationFromDisplayToCamera);
  67. if (camera.getFacing() == CameraFacing.FRONT) {
  68. Log.i(TAG, "Compensating rotation for front camera");
  69. cwNeededRotation = (360 - cwRotationFromDisplayToCamera) % 360;
  70. } else {
  71. cwNeededRotation = cwRotationFromDisplayToCamera;
  72. }
  73. Log.i(TAG, "Clockwise rotation from display to camera: " + cwNeededRotation);
  74. Point theScreenResolution = new Point();
  75. display.getSize(theScreenResolution);
  76. screenResolution = theScreenResolution;
  77. Log.i(TAG, "Screen resolution in current orientation: " + screenResolution);
  78. cameraResolution = CameraConfigurationUtils.findBestPreviewSizeValue(parameters, screenResolution);
  79. Log.i(TAG, "Camera resolution: " + cameraResolution);
  80. bestPreviewSize = CameraConfigurationUtils.findBestPreviewSizeValue(parameters, screenResolution);
  81. Log.i(TAG, "Best available preview size: " + bestPreviewSize);
  82. boolean isScreenPortrait = screenResolution.x < screenResolution.y;
  83. boolean isPreviewSizePortrait = bestPreviewSize.x < bestPreviewSize.y;
  84. if (isScreenPortrait == isPreviewSizePortrait) {
  85. previewSizeOnScreen = bestPreviewSize;
  86. } else {
  87. previewSizeOnScreen = new Point(bestPreviewSize.y, bestPreviewSize.x);
  88. }
  89. Log.i(TAG, "Preview size on screen: " + previewSizeOnScreen);
  90. }
  91. void setDesiredCameraParameters(OpenCamera camera, boolean safeMode) {
  92. Camera theCamera = camera.getCamera();
  93. Camera.Parameters parameters = theCamera.getParameters();
  94. if (parameters == null) {
  95. Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration.");
  96. return;
  97. }
  98. Log.i(TAG, "Initial camera parameters: " + parameters.flatten());
  99. if (safeMode) {
  100. Log.w(TAG, "In camera config safe mode -- most settings will not be honored");
  101. }
  102. // SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
  103. initializeTorch(parameters, safeMode, QRConstants.disableExposure);
  104. CameraConfigurationUtils.setFocus(
  105. parameters,
  106. //是否支持自動(dòng)對(duì)焦
  107. QRConstants.autoFocus,
  108. true,
  109. safeMode);
  110. if (!safeMode) {
  111. //
  112. //CameraConfigurationUtils.setInvertColor(parameters);
  113. CameraConfigurationUtils.setBarcodeSceneMode(parameters);
  114. CameraConfigurationUtils.setVideoStabilization(parameters);
  115. CameraConfigurationUtils.setFocusArea(parameters);
  116. CameraConfigurationUtils.setMetering(parameters);
  117. }
  118. parameters.setPreviewSize(bestPreviewSize.x, bestPreviewSize.y);
  119. theCamera.setParameters(parameters);
  120. theCamera.setDisplayOrientation(cwRotationFromDisplayToCamera);
  121. Camera.Parameters afterParameters = theCamera.getParameters();
  122. Camera.Size afterSize = afterParameters.getPreviewSize();
  123. if (afterSize != null && (bestPreviewSize.x != afterSize.width || bestPreviewSize.y != afterSize.height)) {
  124. Log.w(TAG, "Camera said it supported preview size " + bestPreviewSize.x + 'x' + bestPreviewSize.y +
  125. ", but after setting it, preview size is " + afterSize.width + 'x' + afterSize.height);
  126. bestPreviewSize.x = afterSize.width;
  127. bestPreviewSize.y = afterSize.height;
  128. }
  129. }
  130. Point getBestPreviewSize() {
  131. return bestPreviewSize;
  132. }
  133. Point getPreviewSizeOnScreen() {
  134. return previewSizeOnScreen;
  135. }
  136. Point getCameraResolution() {
  137. return cameraResolution;
  138. }
  139. Point getScreenResolution() {
  140. return screenResolution;
  141. }
  142. int getCWNeededRotation() {
  143. return cwNeededRotation;
  144. }
  145. boolean getTorchState(Camera camera) {
  146. if (camera != null) {
  147. Camera.Parameters parameters = camera.getParameters();
  148. if (parameters != null) {
  149. String flashMode = camera.getParameters().getFlashMode();
  150. return flashMode != null &&
  151. (Camera.Parameters.FLASH_MODE_ON.equals(flashMode) ||
  152. Camera.Parameters.FLASH_MODE_TORCH.equals(flashMode));
  153. }
  154. }
  155. return false;
  156. }
  157. void setTorch(Camera camera, boolean newSetting) {
  158. Camera.Parameters parameters = camera.getParameters();
  159. doSetTorch(parameters, newSetting, false, QRConstants.disableExposure);
  160. camera.setParameters(parameters);
  161. }
  162. private void initializeTorch(Camera.Parameters parameters, boolean safeMode, boolean disableExposure) {
  163. boolean currentSetting = QRConstants.frontLightMode == FrontLightMode.ON;
  164. doSetTorch(parameters, currentSetting, safeMode, disableExposure);
  165. }
  166. private void doSetTorch(Camera.Parameters parameters, boolean newSetting, boolean safeMode, boolean disableExposure) {
  167. CameraConfigurationUtils.setTorch(parameters, newSetting);
  168. if (!safeMode && !disableExposure) {
  169. CameraConfigurationUtils.setBestExposure(parameters, newSetting);
  170. }
  171. }
  172. }
CameraConfigurationUtils.java
  1. @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
  2. public final class CameraConfigurationUtils {
  3. private static final String TAG = "CameraConfiguration";
  4. private static final Pattern SEMICOLON = Pattern.compile(";");
  5. private static final int MIN_PREVIEW_PIXELS = 480 * 320; // normal screen
  6. private static final float MAX_EXPOSURE_COMPENSATION = 1.5f;
  7. private static final float MIN_EXPOSURE_COMPENSATION = 0.0f;
  8. private static final double MAX_ASPECT_DISTORTION = 0.15;
  9. private static final int MIN_FPS = 10;
  10. private static final int MAX_FPS = 20;
  11. private static final int AREA_PER_1000 = 400;
  12. private CameraConfigurationUtils() {
  13. }
  14. public static void setFocus(Camera.Parameters parameters,
  15. boolean autoFocus,
  16. boolean disableContinuous,
  17. boolean safeMode) {
  18. List<String> supportedFocusModes = parameters.getSupportedFocusModes();
  19. String focusMode = null;
  20. if (autoFocus) {
  21. if (safeMode || disableContinuous) {
  22. focusMode = findSettableValue("focus mode",
  23. supportedFocusModes,
  24. Camera.Parameters.FOCUS_MODE_AUTO);
  25. } else {
  26. focusMode = findSettableValue("focus mode",
  27. supportedFocusModes,
  28. Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
  29. Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
  30. Camera.Parameters.FOCUS_MODE_AUTO);
  31. }
  32. }
  33. // Maybe selected auto-focus but not available, so fall through here:
  34. if (!safeMode && focusMode == null) {
  35. focusMode = findSettableValue("focus mode",
  36. supportedFocusModes,
  37. Camera.Parameters.FOCUS_MODE_MACRO,
  38. Camera.Parameters.FOCUS_MODE_EDOF);
  39. }
  40. if (focusMode != null) {
  41. if (focusMode.equals(parameters.getFocusMode())) {
  42. Log.i(TAG, "Focus mode already set to " + focusMode);
  43. } else {
  44. parameters.setFocusMode(focusMode);
  45. }
  46. }
  47. }
  48. public static void setTorch(Camera.Parameters parameters, boolean on) {
  49. List<String> supportedFlashModes = parameters.getSupportedFlashModes();
  50. String flashMode;
  51. if (on) {
  52. flashMode = findSettableValue("flash mode",
  53. supportedFlashModes,
  54. Camera.Parameters.FLASH_MODE_TORCH,
  55. Camera.Parameters.FLASH_MODE_ON);
  56. } else {
  57. flashMode = findSettableValue("flash mode",
  58. supportedFlashModes,
  59. Camera.Parameters.FLASH_MODE_OFF);
  60. }
  61. if (flashMode != null) {
  62. if (flashMode.equals(parameters.getFlashMode())) {
  63. Log.i(TAG, "Flash mode already set to " + flashMode);
  64. } else {
  65. Log.i(TAG, "Setting flash mode to " + flashMode);
  66. parameters.setFlashMode(flashMode);
  67. }
  68. }
  69. }
  70. public static void setBestExposure(Camera.Parameters parameters, boolean lightOn) {
  71. int minExposure = parameters.getMinExposureCompensation();
  72. int maxExposure = parameters.getMaxExposureCompensation();
  73. float step = parameters.getExposureCompensationStep();
  74. if ((minExposure != 0 || maxExposure != 0) && step > 0.0f) {
  75. // Set low when light is on
  76. float targetCompensation = lightOn ? MIN_EXPOSURE_COMPENSATION : MAX_EXPOSURE_COMPENSATION;
  77. int compensationSteps = Math.round(targetCompensation / step);
  78. float actualCompensation = step * compensationSteps;
  79. // Clamp value:
  80. compensationSteps = Math.max(Math.min(compensationSteps, maxExposure), minExposure);
  81. if (parameters.getExposureCompensation() == compensationSteps) {
  82. Log.i(TAG, "Exposure compensation already set to " + compensationSteps + " / " + actualCompensation);
  83. } else {
  84. Log.i(TAG, "Setting exposure compensation to " + compensationSteps + " / " + actualCompensation);
  85. parameters.setExposureCompensation(compensationSteps);
  86. }
  87. } else {
  88. Log.i(TAG, "Camera does not support exposure compensation");
  89. }
  90. }
  91. public static void setBestPreviewFPS(Camera.Parameters parameters) {
  92. setBestPreviewFPS(parameters, MIN_FPS, MAX_FPS);
  93. }
  94. public static void setBestPreviewFPS(Camera.Parameters parameters, int minFPS, int maxFPS) {
  95. List<int[]> supportedPreviewFpsRanges = parameters.getSupportedPreviewFpsRange();
  96. Log.i(TAG, "Supported FPS ranges: " + toString(supportedPreviewFpsRanges));
  97. if (supportedPreviewFpsRanges != null && !supportedPreviewFpsRanges.isEmpty()) {
  98. int[] suitableFPSRange = null;
  99. for (int[] fpsRange : supportedPreviewFpsRanges) {
  100. int thisMin = fpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX];
  101. int thisMax = fpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX];
  102. if (thisMin >= minFPS * 1000 && thisMax <= maxFPS * 1000) {
  103. suitableFPSRange = fpsRange;
  104. break;
  105. }
  106. }
  107. if (suitableFPSRange == null) {
  108. Log.i(TAG, "No suitable FPS range?");
  109. } else {
  110. int[] currentFpsRange = new int[2];
  111. parameters.getPreviewFpsRange(currentFpsRange);
  112. if (Arrays.equals(currentFpsRange, suitableFPSRange)) {
  113. Log.i(TAG, "FPS range already set to " + Arrays.toString(suitableFPSRange));
  114. } else {
  115. Log.i(TAG, "Setting FPS range to " + Arrays.toString(suitableFPSRange));
  116. parameters.setPreviewFpsRange(suitableFPSRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
  117. suitableFPSRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
  118. }
  119. }
  120. }
  121. }
  122. public static void setFocusArea(Camera.Parameters parameters) {
  123. if (parameters.getMaxNumFocusAreas() > 0) {
  124. Log.i(TAG, "Old focus areas: " + toString(parameters.getFocusAreas()));
  125. List<Camera.Area> middleArea = buildMiddleArea(AREA_PER_1000);
  126. Log.i(TAG, "Setting focus area to : " + toString(middleArea));
  127. parameters.setFocusAreas(middleArea);
  128. } else {
  129. Log.i(TAG, "Device does not support focus areas");
  130. }
  131. }
  132. public static void setMetering(Camera.Parameters parameters) {
  133. if (parameters.getMaxNumMeteringAreas() > 0) {
  134. Log.i(TAG, "Old metering areas: " + parameters.getMeteringAreas());
  135. List<Camera.Area> middleArea = buildMiddleArea(AREA_PER_1000);
  136. Log.i(TAG, "Setting metering area to : " + toString(middleArea));
  137. parameters.setMeteringAreas(middleArea);
  138. } else {
  139. Log.i(TAG, "Device does not support metering areas");
  140. }
  141. }
  142. private static List<Camera.Area> buildMiddleArea(int areaPer1000) {
  143. return Collections.singletonList(
  144. new Camera.Area(new Rect(-areaPer1000, -areaPer1000, areaPer1000, areaPer1000), 1));
  145. }
  146. public static void setVideoStabilization(Camera.Parameters parameters) {
  147. if (parameters.isVideoStabilizationSupported()) {
  148. if (parameters.getVideoStabilization()) {
  149. Log.i(TAG, "Video stabilization already enabled");
  150. } else {
  151. Log.i(TAG, "Enabling video stabilization...");
  152. parameters.setVideoStabilization(true);
  153. }
  154. } else {
  155. Log.i(TAG, "This device does not support video stabilization");
  156. }
  157. }
  158. public static void setBarcodeSceneMode(Camera.Parameters parameters) {
  159. if (Camera.Parameters.SCENE_MODE_BARCODE.equals(parameters.getSceneMode())) {
  160. Log.i(TAG, "Barcode scene mode already set");
  161. return;
  162. }
  163. String sceneMode = findSettableValue("scene mode",
  164. parameters.getSupportedSceneModes(),
  165. Camera.Parameters.SCENE_MODE_BARCODE);
  166. if (sceneMode != null) {
  167. parameters.setSceneMode(sceneMode);
  168. }
  169. }
  170. public static void setZoom(Camera.Parameters parameters, double targetZoomRatio) {
  171. if (parameters.isZoomSupported()) {
  172. Integer zoom = indexOfClosestZoom(parameters, targetZoomRatio);
  173. if (zoom == null) {
  174. return;
  175. }
  176. if (parameters.getZoom() == zoom) {
  177. Log.i(TAG, "Zoom is already set to " + zoom);
  178. } else {
  179. Log.i(TAG, "Setting zoom to " + zoom);
  180. parameters.setZoom(zoom);
  181. }
  182. } else {
  183. Log.i(TAG, "Zoom is not supported");
  184. }
  185. }
  186. private static Integer indexOfClosestZoom(Camera.Parameters parameters, double targetZoomRatio) {
  187. List<Integer> ratios = parameters.getZoomRatios();
  188. Log.i(TAG, "Zoom ratios: " + ratios);
  189. int maxZoom = parameters.getMaxZoom();
  190. if (ratios == null || ratios.isEmpty() || ratios.size() != maxZoom + 1) {
  191. Log.w(TAG, "Invalid zoom ratios!");
  192. return null;
  193. }
  194. double target100 = 100.0 * targetZoomRatio;
  195. double smallestDiff = Double.POSITIVE_INFINITY;
  196. int closestIndex = 0;
  197. for (int i = 0; i < ratios.size(); i++) {
  198. double diff = Math.abs(ratios.get(i) - target100);
  199. if (diff < smallestDiff) {
  200. smallestDiff = diff;
  201. closestIndex = i;
  202. }
  203. }
  204. Log.i(TAG, "Chose zoom ratio of " + (ratios.get(closestIndex) / 100.0));
  205. return closestIndex;
  206. }
  207. public static void setInvertColor(Camera.Parameters parameters) {
  208. if (Camera.Parameters.EFFECT_NEGATIVE.equals(parameters.getColorEffect())) {
  209. Log.i(TAG, "Negative effect already set");
  210. return;
  211. }
  212. String colorMode = findSettableValue("color effect",
  213. parameters.getSupportedColorEffects(),
  214. Camera.Parameters.EFFECT_NEGATIVE);
  215. if (colorMode != null) {
  216. parameters.setColorEffect(colorMode);
  217. }
  218. }
  219. public static Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) {
  220. List<Camera.Size> rawSupportedSizes = parameters.getSupportedPreviewSizes();
  221. if (rawSupportedSizes == null) {
  222. Log.w(TAG, "Device returned no supported preview sizes; using default");
  223. Camera.Size defaultSize = parameters.getPreviewSize();
  224. if (defaultSize == null) {
  225. throw new IllegalStateException("Parameters contained no preview size!");
  226. }
  227. return new Point(defaultSize.width, defaultSize.height);
  228. }
  229. // Sort by size, descending
  230. List<Camera.Size> supportedPreviewSizes = new ArrayList<>(rawSupportedSizes);
  231. Collections.sort(supportedPreviewSizes, new Comparator<Camera.Size>() {
  232. @Override
  233. public int compare(Camera.Size a, Camera.Size b) {
  234. int aPixels = a.height * a.width;
  235. int bPixels = b.height * b.width;
  236. if (bPixels < aPixels) {
  237. return -1;
  238. }
  239. if (bPixels > aPixels) {
  240. return 1;
  241. }
  242. return 0;
  243. }
  244. });
  245. if (Log.isLoggable(TAG, Log.INFO)) {
  246. StringBuilder previewSizesString = new StringBuilder();
  247. for (Camera.Size supportedPreviewSize : supportedPreviewSizes) {
  248. previewSizesString.append(supportedPreviewSize.width).append('x')
  249. .append(supportedPreviewSize.height).append(' ');
  250. }
  251. Log.i(TAG, "Supported preview sizes: " + previewSizesString);
  252. }
  253. double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y;
  254. // Remove sizes that are unsuitable
  255. Iterator<Camera.Size> it = supportedPreviewSizes.iterator();
  256. while (it.hasNext()) {
  257. Camera.Size supportedPreviewSize = it.next();
  258. int realWidth = supportedPreviewSize.width;
  259. int realHeight = supportedPreviewSize.height;
  260. if (realWidth * realHeight < MIN_PREVIEW_PIXELS) {
  261. it.remove();
  262. continue;
  263. }
  264. boolean isCandidatePortrait = realWidth < realHeight;
  265. int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth;
  266. int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight;
  267. double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
  268. double distortion = Math.abs(aspectRatio - screenAspectRatio);
  269. if (distortion > MAX_ASPECT_DISTORTION) {
  270. it.remove();
  271. continue;
  272. }
  273. if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) {
  274. Point exactPoint = new Point(realWidth, realHeight);
  275. Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint);
  276. return exactPoint;
  277. }
  278. }
  279. // If no exact match, use largest preview size. This was not a great idea on older devices because
  280. // of the additional computation needed. We're likely to get here on newer Android 4+ devices, where
  281. // the CPU is much more powerful.
  282. if (!supportedPreviewSizes.isEmpty()) {
  283. Camera.Size largestPreview = supportedPreviewSizes.get(0);
  284. Point largestSize = new Point(largestPreview.width, largestPreview.height);
  285. Log.i(TAG, "Using largest suitable preview size: " + largestSize);
  286. return largestSize;
  287. }
  288. // If there is nothing at all suitable, return current preview size
  289. Camera.Size defaultPreview = parameters.getPreviewSize();
  290. if (defaultPreview == null) {
  291. throw new IllegalStateException("Parameters contained no preview size!");
  292. }
  293. Point defaultSize = new Point(defaultPreview.width, defaultPreview.height);
  294. Log.i(TAG, "No suitable preview sizes, using default: " + defaultSize);
  295. return defaultSize;
  296. }
  297. private static String findSettableValue(String name,
  298. Collection<String> supportedValues,
  299. String... desiredValues) {
  300. Log.i(TAG, "Requesting " + name + " value from among: " + Arrays.toString(desiredValues));
  301. Log.i(TAG, "Supported " + name + " values: " + supportedValues);
  302. if (supportedValues != null) {
  303. for (String desiredValue : desiredValues) {
  304. if (supportedValues.contains(desiredValue)) {
  305. Log.i(TAG, "Can set " + name + " to: " + desiredValue);
  306. return desiredValue;
  307. }
  308. }
  309. }
  310. Log.i(TAG, "No supported values match");
  311. return null;
  312. }
  313. private static String toString(Collection<int[]> arrays) {
  314. if (arrays == null || arrays.isEmpty()) {
  315. return "[]";
  316. }
  317. StringBuilder buffer = new StringBuilder();
  318. buffer.append('[');
  319. Iterator<int[]> it = arrays.iterator();
  320. while (it.hasNext()) {
  321. buffer.append(Arrays.toString(it.next()));
  322. if (it.hasNext()) {
  323. buffer.append(", ");
  324. }
  325. }
  326. buffer.append(']');
  327. return buffer.toString();
  328. }
  329. private static String toString(Iterable<Camera.Area> areas) {
  330. if (areas == null) {
  331. return null;
  332. }
  333. StringBuilder result = new StringBuilder();
  334. for (Camera.Area area : areas) {
  335. result.append(area.rect).append(':').append(area.weight).append(' ');
  336. }
  337. return result.toString();
  338. }
  339. public static String collectStats(Camera.Parameters parameters) {
  340. return collectStats(parameters.flatten());
  341. }
  342. public static String collectStats(CharSequence flattenedParams) {
  343. StringBuilder result = new StringBuilder(1000);
  344. result.append("BOARD=").append(Build.BOARD).append('\n');
  345. result.append("BRAND=").append(Build.BRAND).append('\n');
  346. result.append("CPU_ABI=").append(Build.CPU_ABI).append('\n');
  347. result.append("DEVICE=").append(Build.DEVICE).append('\n');
  348. result.append("DISPLAY=").append(Build.DISPLAY).append('\n');
  349. result.append("FINGERPRINT=").append(Build.FINGERPRINT).append('\n');
  350. result.append("HOST=").append(Build.HOST).append('\n');
  351. result.append("ID=").append(Build.ID).append('\n');
  352. result.append("MANUFACTURER=").append(Build.MANUFACTURER).append('\n');
  353. result.append("MODEL=").append(Build.MODEL).append('\n');
  354. result.append("PRODUCT=").append(Build.PRODUCT).append('\n');
  355. result.append("TAGS=").append(Build.TAGS).append('\n');
  356. result.append("TIME=").append(Build.TIME).append('\n');
  357. result.append("TYPE=").append(Build.TYPE).append('\n');
  358. result.append("USER=").append(Build.USER).append('\n');
  359. result.append("VERSION.CODENAME=").append(Build.VERSION.CODENAME).append('\n');
  360. result.append("VERSION.INCREMENTAL=").append(Build.VERSION.INCREMENTAL).append('\n');
  361. result.append("VERSION.RELEASE=").append(Build.VERSION.RELEASE).append('\n');
  362. result.append("VERSION.SDK_INT=").append(Build.VERSION.SDK_INT).append('\n');
  363. if (flattenedParams != null) {
  364. String[] params = SEMICOLON.split(flattenedParams);
  365. Arrays.sort(params);
  366. for (String param : params) {
  367. result.append(param).append('\n');
  368. }
  369. }
  370. return result.toString();
  371. }
  372. }
CameraManager.java
  1. public final class CameraManager {
  2. private static final String TAG = CameraManager.class.getSimpleName();
  3. private static final int MIN_FRAME_WIDTH = 240;
  4. private static final int MIN_FRAME_HEIGHT = 240;
  5. private static final int MAX_FRAME_WIDTH = 1200; // = 5/8 * 1920
  6. private static final int MAX_FRAME_HEIGHT = 675; // = 5/8 * 1080
  7. private final Context context;
  8. private final CameraConfigurationManager configManager;
  9. private OpenCamera camera;
  10. private AutoFocusManager autoFocusManager;
  11. private Rect framingRect;
  12. private Rect framingRectInPreview;
  13. private boolean initialized;
  14. private boolean previewing;
  15. private int requestedCameraId = OpenCameraInterface.NO_REQUESTED_CAMERA;
  16. private int requestedFramingRectWidth;
  17. private int requestedFramingRectHeight;
  18. /**
  19. * Preview frames are delivered here, which we pass on to the registered handler. Make sure to
  20. * clear the handler so it will only receive one message.
  21. */
  22. private final PreviewCallback previewCallback;
  23. public CameraManager(Context context) {
  24. this.context = context;
  25. this.configManager = new CameraConfigurationManager(context);
  26. previewCallback = new PreviewCallback(configManager);
  27. }
  28. /**
  29. * Opens the camera driver and initializes the hardware parameters.
  30. *
  31. * @param holder The surface object which the camera will draw preview frames into.
  32. * @throws IOException Indicates the camera driver failed to open.
  33. */
  34. public synchronized void openDriver(SurfaceHolder holder) throws IOException {
  35. OpenCamera theCamera = camera;
  36. if (theCamera == null) {
  37. theCamera = OpenCameraInterface.open(requestedCameraId);
  38. if (theCamera == null) {
  39. throw new IOException("Camera.open() failed to return object from driver");
  40. }
  41. camera = theCamera;
  42. }
  43. if (!initialized) {
  44. initialized = true;
  45. configManager.initFromCameraParameters(theCamera);
  46. if (requestedFramingRectWidth > 0 && requestedFramingRectHeight > 0) {
  47. setManualFramingRect(requestedFramingRectWidth, requestedFramingRectHeight);
  48. requestedFramingRectWidth = 0;
  49. requestedFramingRectHeight = 0;
  50. }
  51. }
  52. Camera cameraObject = theCamera.getCamera();
  53. Camera.Parameters parameters = cameraObject.getParameters();
  54. String parametersFlattened = parameters == null ? null : parameters.flatten(); // Save these, temporarily
  55. try {
  56. configManager.setDesiredCameraParameters(theCamera, false);
  57. } catch (RuntimeException re) {
  58. // Driver failed
  59. Log.w(TAG, "Camera rejected parameters. Setting only minimal safe-mode parameters");
  60. Log.i(TAG, "Resetting to saved camera params: " + parametersFlattened);
  61. // Reset:
  62. if (parametersFlattened != null) {
  63. parameters = cameraObject.getParameters();
  64. parameters.unflatten(parametersFlattened);
  65. try {
  66. cameraObject.setParameters(parameters);
  67. configManager.setDesiredCameraParameters(theCamera, true);
  68. } catch (RuntimeException re2) {
  69. // Well, darn. Give up
  70. Log.w(TAG, "Camera rejected even safe-mode parameters! No configuration");
  71. }
  72. }
  73. }
  74. cameraObject.setPreviewDisplay(holder);
  75. }
  76. public synchronized boolean isOpen() {
  77. return camera != null;
  78. }
  79. /**
  80. * Closes the camera driver if still in use.
  81. */
  82. public synchronized void closeDriver() {
  83. if (camera != null) {
  84. camera.getCamera().release();
  85. camera = null;
  86. // Make sure to clear these each time we close the camera, so that any scanning rect
  87. // requested by intent is forgotten.
  88. framingRect = null;
  89. framingRectInPreview = null;
  90. }
  91. }
  92. /**
  93. * Asks the camera hardware to begin drawing preview frames to the screen.
  94. */
  95. public synchronized void startPreview() {
  96. OpenCamera theCamera = camera;
  97. if (theCamera != null && !previewing) {
  98. theCamera.getCamera().startPreview();
  99. previewing = true;
  100. autoFocusManager = new AutoFocusManager(context, theCamera.getCamera());
  101. }
  102. }
  103. /**
  104. * Tells the camera to stop drawing preview frames.
  105. */
  106. public synchronized void stopPreview() {
  107. if (autoFocusManager != null) {
  108. autoFocusManager.stop();
  109. autoFocusManager = null;
  110. }
  111. if (camera != null && previewing) {
  112. camera.getCamera().stopPreview();
  113. previewCallback.setHandler(null, 0);
  114. previewing = false;
  115. }
  116. }
  117. /**
  118. * Convenience method for {@link CaptureActivity}
  119. *
  120. * @param newSetting if {@code true}, light should be turned on if currently off. And vice versa.
  121. */
  122. public synchronized void setTorch(boolean newSetting) {
  123. OpenCamera theCamera = camera;
  124. if (theCamera != null) {
  125. if (newSetting != configManager.getTorchState(theCamera.getCamera())) {
  126. boolean wasAutoFocusManager = autoFocusManager != null;
  127. if (wasAutoFocusManager) {
  128. autoFocusManager.stop();
  129. autoFocusManager = null;
  130. }
  131. configManager.setTorch(theCamera.getCamera(), newSetting);
  132. if (wasAutoFocusManager) {
  133. autoFocusManager = new AutoFocusManager(context, theCamera.getCamera());
  134. autoFocusManager.start();
  135. }
  136. }
  137. }
  138. }
  139. /**
  140. * A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
  141. * in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
  142. * respectively.
  143. *
  144. * @param handler The handler to send the message to.
  145. * @param message The what field of the message to be sent.
  146. */
  147. public synchronized void requestPreviewFrame(Handler handler, int message) {
  148. OpenCamera theCamera = camera;
  149. if (theCamera != null && previewing) {
  150. previewCallback.setHandler(handler, message);
  151. theCamera.getCamera().setOneShotPreviewCallback(previewCallback);
  152. }
  153. }
  154. /**
  155. * Calculates the framing rect which the UI should draw to show the user where to place the
  156. * barcode. This target helps with alignment as well as forces the user to hold the device
  157. * far enough away to ensure the image will be in focus.
  158. *
  159. * @return The rectangle to draw on screen in window coordinates.
  160. */
  161. public synchronized Rect getFramingRect() {
  162. if (framingRect == null) {
  163. if (camera == null) {
  164. return null;
  165. }
  166. Point screenResolution = configManager.getScreenResolution();
  167. if (screenResolution == null) {
  168. // Called early, before init even finished
  169. return null;
  170. }
  171. int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
  172. int height = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
  173. //保持掃描框?qū)捀咭恢?/div>
  174. int finalSize = height;
  175. if (height > width) {
  176. finalSize = width;
  177. }
  178. int leftOffset = (screenResolution.x - finalSize) / 2;
  179. int topOffset = (screenResolution.y - finalSize) / 2;
  180. framingRect = new Rect(leftOffset, topOffset, leftOffset + finalSize, topOffset + finalSize);
  181. Log.d(TAG, "Calculated framing rect: " + framingRect + " width =" + width + " height = " + height +
  182. " screenResolution.x = " + screenResolution.x + " screenResolution.y = " + screenResolution.y);
  183. }
  184. return framingRect;
  185. }
  186. private static int findDesiredDimensionInRange(int resolution, int hardMin, int hardMax) {
  187. int dim = 5 * resolution / 8; // Target 5/8 of each dimension
  188. if (dim < hardMin) {
  189. return hardMin;
  190. }
  191. if (dim > hardMax) {
  192. return hardMax;
  193. }
  194. return dim;
  195. }
  196. /**
  197. * Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
  198. * not UI / screen.
  199. *
  200. * @return {@link Rect} expressing barcode scan area in terms of the preview size
  201. */
  202. public synchronized Rect getFramingRectInPreview() {
  203. if (framingRectInPreview == null) {
  204. Rect framingRect = getFramingRect();
  205. if (framingRect == null) {
  206. return null;
  207. }
  208. Rect rect = new Rect(framingRect);
  209. Point cameraResolution = configManager.getCameraResolution();
  210. Point screenResolution = configManager.getScreenResolution();
  211. if (cameraResolution == null || screenResolution == null) {
  212. // Called early, before init even finished
  213. return null;
  214. }
  215. rect.left = rect.left * cameraResolution.x / screenResolution.x;
  216. rect.right = rect.right * cameraResolution.x / screenResolution.x;
  217. rect.top = rect.top * cameraResolution.y / screenResolution.y;
  218. rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
  219. framingRectInPreview = rect;
  220. }
  221. return framingRectInPreview;
  222. }
  223. /**
  224. * Allows third party apps to specify the camera ID, rather than determine
  225. * it automatically based on available cameras and their orientation.
  226. *
  227. * @param cameraId camera ID of the camera to use. A negative value means "no preference".
  228. */
  229. public synchronized void setManualCameraId(int cameraId) {
  230. requestedCameraId = cameraId;
  231. }
  232. /**
  233. * Allows third party apps to specify the scanning rectangle dimensions, rather than determine
  234. * them automatically based on screen resolution.
  235. *
  236. * @param width The width in pixels to scan.
  237. * @param height The height in pixels to scan.
  238. */
  239. public synchronized void setManualFramingRect(int width, int height) {
  240. if (initialized) {
  241. Point screenResolution = configManager.getScreenResolution();
  242. if (width > screenResolution.x) {
  243. width = screenResolution.x;
  244. }
  245. if (height > screenResolution.y) {
  246. height = screenResolution.y;
  247. }
  248. int leftOffset = (screenResolution.x - width) / 2;
  249. int topOffset = (screenResolution.y - height) / 2;
  250. framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
  251. Log.d(TAG, "Calculated manual framing rect: " + framingRect);
  252. framingRectInPreview = null;
  253. } else {
  254. requestedFramingRectWidth = width;
  255. requestedFramingRectHeight = height;
  256. }
  257. }
  258. /**
  259. * A factory method to build the appropriate LuminanceSource object based on the format
  260. * of the preview buffers, as described by Camera.Parameters.
  261. *
  262. * @param data A preview frame.
  263. * @param width The width of the image.
  264. * @param height The height of the image.
  265. * @return A PlanarYUVLuminanceSource instance.
  266. */
  267. public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
  268. Rect rect = getFramingRectInPreview();
  269. if (rect == null) {
  270. return null;
  271. }
  272. // Go ahead and assume it's YUV rather than die.
  273. return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
  274. rect.width(), rect.height(), false);
  275. }
  276. public void openLight() {
  277. if (camera != null && camera.getCamera() != null) {
  278. Camera.Parameters parameter = camera.getCamera().getParameters();
  279. parameter.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
  280. camera.getCamera().setParameters(parameter);
  281. }
  282. }
  283. public void offLight() {
  284. if (camera != null && camera.getCamera() != null) {
  285. Camera.Parameters parameter = camera.getCamera().getParameters();
  286. parameter.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
  287. camera.getCamera().setParameters(parameter);
  288. }
  289. }
  290. }
FrontLightMode.java
  1. public enum FrontLightMode {
  2. /** Always on. */
  3. ON,
  4. /** On only when ambient light is low. */
  5. AUTO,
  6. /** Always off. */
  7. OFF
  8. /* private static FrontLightMode parse(String modeString) {
  9. return modeString == null ? OFF : valueOf(modeString);
  10. }
  11. public static FrontLightMode readPref(SharedPreferences sharedPrefs) {
  12. return parse(sharedPrefs.getString(PreferencesActivity.KEY_FRONT_LIGHT_MODE, OFF.toString()));
  13. }*/
  14. }
PreviewCallback.java
  1. final class PreviewCallback implements Camera.PreviewCallback {
  2. private static final String TAG = PreviewCallback.class.getSimpleName();
  3. private final CameraConfigurationManager configManager;
  4. private Handler previewHandler;
  5. private int previewMessage;
  6. PreviewCallback(CameraConfigurationManager configManager) {
  7. this.configManager = configManager;
  8. }
  9. void setHandler(Handler previewHandler, int previewMessage) {
  10. this.previewHandler = previewHandler;
  11. this.previewMessage = previewMessage;
  12. }
  13. @Override
  14. public void onPreviewFrame(byte[] data, Camera camera) {
  15. Point cameraResolution = configManager.getCameraResolution();
  16. Handler thePreviewHandler = previewHandler;
  17. if (cameraResolution != null && thePreviewHandler != null) {
  18. //給DecodeHandler發(fā)消息
  19. Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
  20. cameraResolution.y, data);
  21. message.sendToTarget();
  22. previewHandler = null;
  23. } else {
  24. Log.d(TAG, "Got preview callback, but no handler or resolution available");
  25. }
  26. }
  27. }
QRConstants.java
  1. public class QRConstants {
  2. public static boolean vibrateEnable = true;
  3. public static boolean beepEnable = true;
  4. public static FrontLightMode frontLightMode = FrontLightMode.OFF;
  5. public static boolean disableExposure = true;
  6. public static boolean autoFocus = true;
  7. public static final String KEY_AUTO_FOCUS = "preferences_auto_focus";
  8. }
Constant.java
  1. public class Constant {
  2. public static final int DECODE = 1;
  3. public static final int DECODE_FAILED = 2;
  4. public static final int DECODE_SUCCEEDED = 3;
  5. public static final int LAUNCH_PRODUCT_QUERY = 4;
  6. public static final int QUIT = 5;
  7. public static final int RESTART_PREVIEW = 6;
  8. public static final int RETURN_SCAN_RESULT = 7;
  9. public static final int FLASH_OPEN = 8;
  10. public static final int FLASH_CLOSE = 9;
  11. public static final int REQUEST_IMAGE = 10;
  12. public static final String CODED_CONTENT = "codedContent";
  13. public static final String CODED_BITMAP = "codedBitmap";
  14. /*傳遞的zxingconfing*/
  15. public static final String INTENT_ZXING_CONFIG = "zxingConfig";
  16. }
AmbientLightManager.java
  1. public final class AmbientLightManager implements SensorEventListener {
  2. private static final float TOO_DARK_LUX = 45.0f;
  3. private static final float BRIGHT_ENOUGH_LUX = 450.0f;
  4. private final Context context;
  5. private CameraManager cameraManager;
  6. private Sensor lightSensor;
  7. public AmbientLightManager(Context context) {
  8. this.context = context;
  9. }
  10. public void start(CameraManager cameraManager) {
  11. this.cameraManager = cameraManager;
  12. SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
  13. if (QRConstants.frontLightMode == FrontLightMode.AUTO) {
  14. SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
  15. lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
  16. if (lightSensor != null) {
  17. sensorManager.registerListener(this, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);
  18. }
  19. }
  20. }
  21. public void stop() {
  22. if (lightSensor != null) {
  23. SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
  24. sensorManager.unregisterListener(this);
  25. cameraManager = null;
  26. lightSensor = null;
  27. }
  28. }
  29. @Override
  30. public void onSensorChanged(SensorEvent sensorEvent) {
  31. float ambientLightLux = sensorEvent.values[0];
  32. if (cameraManager != null) {
  33. if (ambientLightLux <= TOO_DARK_LUX) {
  34. cameraManager.setTorch(true);
  35. } else if (ambientLightLux >= BRIGHT_ENOUGH_LUX) {
  36. cameraManager.setTorch(false);
  37. }
  38. }
  39. }
  40. @Override
  41. public void onAccuracyChanged(Sensor sensor, int accuracy) {
  42. // do nothing
  43. }
  44. }
BeepManager.java
  1. public final class BeepManager implements MediaPlayer.OnCompletionListener,
  2. MediaPlayer.OnErrorListener, Closeable {
  3. private static final String TAG = BeepManager.class.getSimpleName();
  4. private static final float BEEP_VOLUME = 0.10f;
  5. private static final long VIBRATE_DURATION = 200L;
  6. private final Activity activity;
  7. private MediaPlayer mediaPlayer;
  8. private boolean playBeep;
  9. private boolean vibrate;
  10. public BeepManager(Activity activity) {
  11. this.activity = activity;
  12. this.mediaPlayer = null;
  13. updatePrefs();
  14. }
  15. public boolean isPlayBeep() {
  16. return playBeep;
  17. }
  18. public void setPlayBeep(boolean playBeep) {
  19. this.playBeep = playBeep;
  20. }
  21. public boolean isVibrate() {
  22. return vibrate;
  23. }
  24. public void setVibrate(boolean vibrate) {
  25. this.vibrate = vibrate;
  26. }
  27. public synchronized void updatePrefs() {
  28. if (playBeep && mediaPlayer == null) {
  29. // The volume on STREAM_SYSTEM is not adjustable, and users found it
  30. // too loud,
  31. // so we now play on the music stream.
  32. // 設(shè)置activity音量控制鍵控制的音頻流
  33. activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
  34. mediaPlayer = buildMediaPlayer(activity);
  35. }
  36. }
  37. /**
  38. * 開啟響鈴和震動(dòng)
  39. */
  40. @SuppressLint("MissingPermission")
  41. public synchronized void playBeepSoundAndVibrate() {
  42. if (playBeep && mediaPlayer != null) {
  43. mediaPlayer.start();
  44. }
  45. if (vibrate) {
  46. Vibrator vibrator = (Vibrator) activity
  47. .getSystemService(Context.VIBRATOR_SERVICE);
  48. vibrator.vibrate(VIBRATE_DURATION);
  49. }
  50. }
  51. /**
  52. * 創(chuàng)建MediaPlayer
  53. *
  54. * @param activity
  55. * @return
  56. */
  57. private MediaPlayer buildMediaPlayer(Context activity) {
  58. MediaPlayer mediaPlayer = new MediaPlayer();
  59. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  60. // 監(jiān)聽是否播放完成
  61. mediaPlayer.setOnCompletionListener(this);
  62. mediaPlayer.setOnErrorListener(this);
  63. // 配置播放資源
  64. try {
  65. AssetFileDescriptor file = activity.getResources()
  66. .openRawResourceFd(R.raw.beep);
  67. try {
  68. mediaPlayer.setDataSource(file.getFileDescriptor(),
  69. file.getStartOffset(), file.getLength());
  70. } finally {
  71. file.close();
  72. }
  73. // 設(shè)置音量
  74. mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
  75. mediaPlayer.prepare();
  76. return mediaPlayer;
  77. } catch (IOException ioe) {
  78. Log.w(TAG, ioe);
  79. mediaPlayer.release();
  80. return null;
  81. }
  82. }
  83. @Override
  84. public void onCompletion(MediaPlayer mp) {
  85. // When the beep has finished playing, rewind to queue up another one.
  86. mp.seekTo(0);
  87. }
  88. @Override
  89. public synchronized boolean onError(MediaPlayer mp, int what, int extra) {
  90. if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
  91. // we are finished, so put up an appropriate error toast if required
  92. // and finish
  93. activity.finish();
  94. } else {
  95. // possibly media player error, so release and recreate
  96. mp.release();
  97. mediaPlayer = null;
  98. updatePrefs();
  99. }
  100. return true;
  101. }
  102. @Override
  103. public synchronized void close() {
  104. if (mediaPlayer != null) {
  105. mediaPlayer.release();
  106. mediaPlayer = null;
  107. }
  108. }
  109. }
CaptureActivity.java
  1. public class CaptureActivity extends Activity implements SurfaceHolder.Callback, View.OnClickListener {
  2. static {
  3. AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);//處理api 5.1以下手機(jī)不兼容問題
  4. }
  5. private static final String TAG = CaptureActivity.class.getSimpleName();
  6. private ImageView mBackmImg;
  7. private TextView mTitle;
  8. public int REQ_ID_GALLERY = 0;
  9. public static boolean isLightOn = false;
  10. private IMResUtil mImResUtil;
  11. public static void startAction(Activity activity, Bundle bundle, int requestCode) {
  12. Intent intent = new Intent(activity, CaptureActivity.class);
  13. intent.putExtras(bundle);
  14. activity.startActivityForResult(intent, requestCode);
  15. }
  16. private CameraManager cameraManager;
  17. private CaptureActivityHandler handler;
  18. private ViewfinderView viewfinderView;
  19. private boolean hasSurface;
  20. private Collection<BarcodeFormat> decodeFormats;
  21. private String characterSet;
  22. private InactivityTimer inactivityTimer;
  23. private BeepManager beepManager;
  24. private AmbientLightManager ambientLightManager;
  25. private LinearLayout bottomLayout;
  26. private TextView flashLightTv;
  27. private ImageView flashLightIv;
  28. private LinearLayout flashLightLayout;
  29. private LinearLayout albumLayout;
  30. private ZxingConfig config;
  31. private ImageView img_phone;
  32. public ViewfinderView getViewfinderView() {
  33. return viewfinderView;
  34. }
  35. public Handler getHandler() {
  36. return handler;
  37. }
  38. public CameraManager getCameraManager() {
  39. return cameraManager;
  40. }
  41. @Override
  42. protected void onCreate(Bundle savedInstanceState) {
  43. super.onCreate(savedInstanceState);
  44. mImResUtil = new IMResUtil(this);
  45. setContentView(mImResUtil.getLayout("activity_device_qrcode_capture"));
  46. //設(shè)置浸入式狀態(tài)欄
  47. setColor(this, Color.BLACK);
  48. hasSurface = false;
  49. inactivityTimer = new InactivityTimer(this);
  50. ambientLightManager = new AmbientLightManager(this);
  51. /*先獲取配置信息*/
  52. try {
  53. config = (ZxingConfig) getIntent().getExtras().get(Constant.INTENT_ZXING_CONFIG);
  54. } catch (Exception e) {
  55. Log.i("config", e.toString());
  56. }
  57. if (config == null) {
  58. config = new ZxingConfig();
  59. }
  60. beepManager = new BeepManager(this);
  61. beepManager.setPlayBeep(config.isPlayBeep());
  62. beepManager.setVibrate(config.isShake());
  63. initView(getIntent().getExtras());
  64. onEvent(getIntent().getExtras());
  65. }
  66. private void initView(Bundle bundle) {
  67. //判斷是否為橫屏狀態(tài)
  68. if ("landscape".equals(bundle.getString("portraitOrLandscape"))) {
  69. setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  70. }
  71. mBackmImg = (ImageView) findViewById(mImResUtil.getId("iv_qr_back"));
  72. mTitle = (TextView) findViewById(mImResUtil.getId("tv_qr_title"));
  73. viewfinderView = (ViewfinderView) findViewById(mImResUtil.getId("vv_qr_viewfinderView"));
  74. flashLightTv = (TextView) findViewById(mImResUtil.getId("flashLightTv"));
  75. bottomLayout = (LinearLayout) findViewById(mImResUtil.getId("bottomLayout"));
  76. flashLightIv = (ImageView) findViewById(mImResUtil.getId("flashLightIv"));
  77. img_phone = (ImageView) findViewById(mImResUtil.getId("img_phone"));
  78. flashLightLayout = (LinearLayout) findViewById(mImResUtil.getId("flashLightLayout"));
  79. flashLightLayout.setOnClickListener(this);
  80. albumLayout = (LinearLayout) findViewById(mImResUtil.getId("albumLayout"));
  81. albumLayout.setOnClickListener(this);
  82. }
  83. private void onEvent(Bundle bundle) {
  84. switchVisibility(bottomLayout, config.isShowbottomLayout());
  85. switchVisibility(flashLightLayout, config.isShowFlashLight());
  86. switchVisibility(albumLayout, config.isShowAlbum());
  87. flashLightIv.setImageResource(R.drawable.device_qrcode_scan_flash_off);
  88. img_phone.setImageResource(R.drawable.ic_photo);
  89. /*有閃光燈就顯示手電筒按鈕 否則不顯示*/
  90. if (isSupportCameraLedFlash(getPackageManager())) {
  91. flashLightLayout.setVisibility(View.VISIBLE);
  92. } else {
  93. flashLightLayout.setVisibility(View.GONE);
  94. }
  95. /********************新增 END*****************************/
  96. mBackmImg.setOnClickListener(this);
  97. if (bundle == null) {
  98. return;
  99. }
  100. String titileText = bundle.getString("titileText");
  101. if (titileText != null && !titileText.isEmpty()) {
  102. mTitle.setText(titileText);
  103. }
  104. String headColor = bundle.getString("headColor");
  105. mTitle.setTextColor(Color.parseColor(headColor));
  106. float headSize = bundle.getFloat("headSize");
  107. if (headSize > 0) {
  108. mTitle.setTextSize(headSize);
  109. }
  110. }
  111. /**
  112. * 沉浸式狀態(tài)欄
  113. *
  114. * @param activity
  115. * @param color
  116. */
  117. public static void setColor(Activity activity, int color) {
  118. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  119. // 設(shè)置狀態(tài)欄透明
  120. activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  121. // 生成一個(gè)狀態(tài)欄大小的矩形
  122. View statusView = createStatusView(activity, color);
  123. // 添加 statusView 到布局中
  124. ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
  125. decorView.addView(statusView);
  126. // 設(shè)置根布局的參數(shù)
  127. ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
  128. rootView.setFitsSystemWindows(true);
  129. rootView.setClipToPadding(true);
  130. }
  131. }
  132. /**
  133. * 繪制一個(gè)和狀態(tài)欄登高的矩形
  134. *
  135. * @param activity
  136. * @param color
  137. */
  138. private static View createStatusView(Activity activity, int color) {
  139. // 獲得狀態(tài)欄高度
  140. int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
  141. int statusBarHeight = activity.getResources().getDimensionPixelSize(resourceId);
  142. View statusView = new View(activity);
  143. LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);
  144. statusView.setLayoutParams(params);
  145. statusView.setBackgroundColor(color);
  146. return statusView;
  147. }
  148. @Override
  149. public void onClick(View v) {
  150. int id = v.getId();
  151. if (id == mImResUtil.getId("iv_qr_back")) {
  152. this.finish();
  153. } else if (id == mImResUtil.getId("albumLayout")) {//打開相冊(cè)
  154. // Intent intent = new Intent();
  155. // intent.setType("image/*");
  156. // intent.setAction(Intent.ACTION_GET_CONTENT);
  157. // intent.addCategory(Intent.CATEGORY_OPENABLE);
  158. // startActivityForResult(intent, REQ_ID_GALLERY);
  159. /*打開相冊(cè)*/
  160. Intent intent = new Intent();
  161. intent.setAction(Intent.ACTION_PICK);
  162. intent.setType("image/*");
  163. startActivityForResult(intent, REQ_ID_GALLERY);
  164. } else if (id == mImResUtil.getId("flashLightLayout")) {//打開手電筒感應(yīng)部分
  165. if (isLightOn) {
  166. isLightOn = false;
  167. cameraManager.offLight();
  168. switchFlashImg(9);
  169. } else {
  170. isLightOn = true;
  171. cameraManager.openLight();
  172. switchFlashImg(8);
  173. }
  174. }
  175. }
  176. @Override
  177. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  178. super.onActivityResult(requestCode, resultCode, data);
  179. if (requestCode == REQ_ID_GALLERY) {
  180. if (resultCode == RESULT_OK) {
  181. Uri uri = data.getData();
  182. if (uri != null) {
  183. String path = FileUtil.checkPicturePath(CaptureActivity.this, uri);//Device.getActivity()
  184. BitmapFactory.Options bmOptions = new BitmapFactory.Options();
  185. bmOptions.inJustDecodeBounds = false;
  186. bmOptions.inPurgeable = true;
  187. Bitmap bmp = BitmapFactory.decodeFile(path, bmOptions);
  188. decodeQRCode(bmp, this);
  189. }
  190. }
  191. }
  192. //-----------------------------------------------------
  193. if (requestCode == Constant.REQUEST_IMAGE && resultCode == RESULT_OK) {
  194. String path = ImageUtil.getImageAbsolutePath(this, data.getData());
  195. Log.e(TAG, "onActivityResult: -------二維碼:path" + path);
  196. BitmapFactory.Options bmOptions = new BitmapFactory.Options();
  197. bmOptions.inJustDecodeBounds = false;
  198. bmOptions.inPurgeable = true;
  199. Bitmap bmp = BitmapFactory.decodeFile(path, bmOptions);
  200. decodeQRCode(bmp, this);
  201. }
  202. }
  203. /**
  204. * 解析二維碼圖片
  205. *
  206. * @param bitmap 要解析的二維碼圖片
  207. */
  208. public final Map<DecodeHintType, Object> HINTS = new EnumMap<>(DecodeHintType.class);
  209. @SuppressLint("StaticFieldLeak")
  210. public void decodeQRCode(final Bitmap bitmap, final Activity activity) {
  211. new AsyncTask<Void, Void, String>() {
  212. @Override
  213. protected String doInBackground(Void... params) {
  214. try {
  215. int width = bitmap.getWidth();
  216. int height = bitmap.getHeight();
  217. int[] pixels = new int[width * height];
  218. bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
  219. RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);
  220. Result result = new MultiFormatReader().decode(new BinaryBitmap(new HybridBinarizer(source)), HINTS);
  221. String url = "解析失敗";
  222. if (result != null && result.getText() != null) {
  223. url = result.getText();
  224. }
  225. Intent resultIntent = new Intent();
  226. Bundle bundle = new Bundle();
  227. bundle.putString(Constant.CODED_CONTENT, url);
  228. resultIntent.putExtras(bundle);
  229. activity.setResult(RESULT_OK, resultIntent);
  230. CaptureActivity.this.finish();
  231. return result.getText();
  232. } catch (Exception e) {
  233. return null;
  234. }
  235. }
  236. @Override
  237. protected void onPostExecute(String result) {
  238. Log.d("CaptureActivity", "result=" + result);
  239. Toast.makeText(CaptureActivity.this, "解析失敗,換個(gè)圖片試一下", Toast.LENGTH_LONG).show();
  240. }
  241. }.execute();
  242. }
  243. @Override
  244. protected void onResume() {
  245. super.onResume();
  246. cameraManager = new CameraManager(getApplication());
  247. viewfinderView.setCameraManager(cameraManager);
  248. handler = null;
  249. beepManager.updatePrefs();
  250. ambientLightManager.start(cameraManager);
  251. inactivityTimer.onResume();
  252. decodeFormats = null;
  253. characterSet = null;
  254. SurfaceView surfaceView = (SurfaceView) findViewById(mImResUtil.getId("device_qrcode_preview_view"));
  255. SurfaceHolder surfaceHolder = surfaceView.getHolder();
  256. if (hasSurface) {
  257. initCamera(surfaceHolder);
  258. } else {
  259. surfaceHolder.addCallback(this);
  260. }
  261. }
  262. @Override
  263. protected void onPause() {
  264. if (handler != null) {
  265. handler.quitSynchronously();
  266. handler = null;
  267. }
  268. inactivityTimer.onPause();
  269. ambientLightManager.stop();
  270. beepManager.close();
  271. cameraManager.closeDriver();
  272. if (!hasSurface) {
  273. SurfaceView surfaceView = (SurfaceView) findViewById(mImResUtil.getId("device_qrcode_preview_view"));
  274. SurfaceHolder surfaceHolder = surfaceView.getHolder();
  275. surfaceHolder.removeCallback(this);
  276. }
  277. super.onPause();
  278. }
  279. @Override
  280. protected void onDestroy() {
  281. inactivityTimer.shutdown();
  282. super.onDestroy();
  283. }
  284. private void initCamera(SurfaceHolder surfaceHolder) {
  285. if (surfaceHolder == null) {
  286. throw new IllegalStateException("No SurfaceHolder provided");
  287. }
  288. if (cameraManager.isOpen()) {
  289. Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?");
  290. return;
  291. }
  292. try {
  293. cameraManager.openDriver(surfaceHolder);
  294. // Creating the handler starts the preview, which can also throw a RuntimeException.
  295. if (handler == null) {
  296. handler = new CaptureActivityHandler(this, decodeFormats, characterSet, cameraManager);
  297. }
  298. } catch (IOException ioe) {
  299. Log.w(TAG, ioe);
  300. } catch (RuntimeException e) {
  301. // Barcode Scanner has seen crashes in the wild of this variety:
  302. // java.?lang.?RuntimeException: Fail to connect to camera service
  303. Log.e(TAG, "Unexpected error initializing camera", e);
  304. }
  305. }
  306. public void drawViewfinder() {
  307. viewfinderView.drawViewfinder();
  308. }
  309. public void handleDecode(Result rawResult, Bitmap barcode, float scaleFactor) {
  310. Log.d("wxl", "rawResult=" + rawResult);
  311. boolean fromLiveScan = barcode != null;
  312. if (fromLiveScan) {
  313. String resultString = rawResult.getText();
  314. Log.e("wxl", "rawResult=" + rawResult.getText());
  315. beepManager.playBeepSoundAndVibrate();
  316. Intent resultIntent = new Intent();
  317. Bundle bundle = new Bundle();
  318. bundle.putString(Constant.CODED_CONTENT, resultString);
  319. resultIntent.putExtras(bundle);
  320. this.setResult(RESULT_OK, resultIntent);
  321. } else {
  322. // this.setResult(RESULT_OK, resultIntent);
  323. Toast.makeText(CaptureActivity.this, "掃描失敗", Toast.LENGTH_SHORT).show();
  324. }
  325. CaptureActivity.this.finish();
  326. }
  327. @Override
  328. public void surfaceCreated(SurfaceHolder holder) {
  329. if (holder == null) {
  330. Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!");
  331. }
  332. if (!hasSurface) {
  333. hasSurface = true;
  334. initCamera(holder);
  335. }
  336. }
  337. @Override
  338. public void surfaceDestroyed(SurfaceHolder holder) {
  339. hasSurface = false;
  340. }
  341. @Override
  342. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  343. }
  344. /********************新增代碼 start: **************************/
  345. private void switchVisibility(View view, boolean b) {
  346. if (b) {
  347. view.setVisibility(View.VISIBLE);
  348. } else {
  349. view.setVisibility(View.GONE);
  350. }
  351. }
  352. /**
  353. * @param pm
  354. *
  355. * @return 是否有閃光燈
  356. */
  357. public static boolean isSupportCameraLedFlash(PackageManager pm) {
  358. if (pm != null) {
  359. FeatureInfo[] features = pm.getSystemAvailableFeatures();
  360. if (features != null) {
  361. for (FeatureInfo f : features) {
  362. if (f != null && PackageManager.FEATURE_CAMERA_FLASH.equals(f.name)) {
  363. return true;
  364. }
  365. }
  366. }
  367. }
  368. return false;
  369. }
  370. /**
  371. * @param flashState 切換閃光燈圖片
  372. */
  373. public void switchFlashImg(int flashState) {
  374. if (flashState == Constant.FLASH_OPEN) {
  375. flashLightIv.setImageResource(R.drawable.device_qrcode_scan_flash_on);//ic_open
  376. flashLightTv.setText("關(guān)閉閃光燈");
  377. } else {
  378. flashLightIv.setImageResource(R.drawable.device_qrcode_scan_flash_off);//ic_close
  379. flashLightTv.setText("打開閃光燈");
  380. }
  381. }
  382. /********************新增代碼 END*****************************/
  383. }
CaptureActivityHandler.java
  1. public final class CaptureActivityHandler extends Handler {
  2. private static final String TAG = CaptureActivityHandler.class.getSimpleName();
  3. private final CaptureActivity activity;
  4. private final DecodeThread decodeThread;
  5. private State state;
  6. private final CameraManager cameraManager;
  7. private final IMResUtil mImResUtil;
  8. // private RelativeLayout mLightLinearLay;//LinearLayout 手電筒的線性布局
  9. private enum State {
  10. PREVIEW, SUCCESS, DONE
  11. }
  12. public CaptureActivityHandler(CaptureActivity activity, Collection<BarcodeFormat> decodeFormats, String characterSet, CameraManager cameraManager) {
  13. this.activity = activity;
  14. mImResUtil = new IMResUtil(activity);
  15. decodeThread = new DecodeThread(activity, decodeFormats, characterSet, new ViewfinderResultPointCallback(activity.getViewfinderView()));
  16. decodeThread.start();
  17. state = State.SUCCESS;
  18. // Start ourselves capturing previews and decoding.
  19. this.cameraManager = cameraManager;
  20. cameraManager.startPreview();
  21. Log.d(TAG, "CaptureActivityHandler " + CaptureActivityHandler.class.toString());
  22. restartPreviewAndDecode();
  23. }
  24. @Override
  25. public void handleMessage(Message message) {
  26. int what = message.what;
  27. if (what == mImResUtil.getId("device_qrcode_restart_preview")) {
  28. restartPreviewAndDecode();
  29. } else if (what == mImResUtil.getId("device_qrcode_decode_succeeded")) {
  30. state = State.SUCCESS;
  31. Bundle bundle = message.getData();
  32. Bitmap barcode = null;
  33. float scaleFactor = 1.0f;
  34. if (bundle != null) {
  35. byte[] compressedBitmap = bundle.getByteArray(DecodeThread.BARCODE_BITMAP);
  36. if (compressedBitmap != null) {
  37. barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null);
  38. // Mutable copy:
  39. barcode = barcode.copy(Bitmap.Config.ARGB_8888, true);
  40. }
  41. scaleFactor = bundle.getFloat(DecodeThread.BARCODE_SCALED_FACTOR);
  42. }
  43. activity.handleDecode((Result) message.obj, barcode, scaleFactor);
  44. } else if (what == mImResUtil.getId("device_qrcode_decode_failed")) {
  45. state = State.PREVIEW;
  46. cameraManager.requestPreviewFrame(decodeThread.getHandler(), mImResUtil.getId("device_qrcode_decode"));
  47. } else if (what == mImResUtil.getId("device_qrcode_return_scan_result")) {
  48. activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
  49. activity.finish();
  50. } else if (what == mImResUtil.getId("device_qrcode_launch_product_query")) {
  51. String url = (String) message.obj;
  52. Intent intent = new Intent(Intent.ACTION_VIEW);
  53. intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
  54. intent.setData(Uri.parse(url));
  55. ResolveInfo resolveInfo = activity.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
  56. String browserPackageName = null;
  57. if (resolveInfo != null && resolveInfo.activityInfo != null) {
  58. browserPackageName = resolveInfo.activityInfo.packageName;
  59. Log.d(TAG, "Using browser in package " + browserPackageName);
  60. }
  61. // Needed for default Android browser / Chrome only apparently
  62. if ("com.android.browser".equals(browserPackageName) || "com.android.chrome".equals(browserPackageName)) {
  63. intent.setPackage(browserPackageName);
  64. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  65. intent.putExtra(Browser.EXTRA_APPLICATION_ID, browserPackageName);
  66. }
  67. try {
  68. activity.startActivity(intent);
  69. } catch (ActivityNotFoundException ignored) {
  70. Log.w(TAG, "Can't find anything to handle VIEW of URI " + url);
  71. }
  72. }
  73. }
  74. public void quitSynchronously() {
  75. state = State.DONE;
  76. cameraManager.stopPreview();
  77. Message quit = Message.obtain(decodeThread.getHandler(), mImResUtil.getId("device_qrcode_quit"));
  78. quit.sendToTarget();
  79. try {
  80. // Wait at most half a second; should be enough time, and onPause() will timeout quickly
  81. decodeThread.join(500L);
  82. } catch (InterruptedException e) {
  83. // continue
  84. }
  85. // Be absolutely sure we don't send any queued up messages
  86. removeMessages(mImResUtil.getId("device_qrcode_decode_succeeded"));
  87. removeMessages(mImResUtil.getId("device_qrcode_decode_failed"));
  88. }
  89. private void restartPreviewAndDecode() {
  90. if (state == State.SUCCESS) {
  91. state = State.PREVIEW;
  92. //decodeThread.getHandler()拿到DecodeHandler
  93. cameraManager.requestPreviewFrame(decodeThread.getHandler(), mImResUtil.getId("device_qrcode_decode"));
  94. activity.drawViewfinder();
  95. }
  96. }
  97. }
DecodeFormatManager.java
  1. final class DecodeFormatManager {
  2. private static final Pattern COMMA_PATTERN = Pattern.compile(",");
  3. // static final Set<BarcodeFormat> PRODUCT_FORMATS;
  4. // static final Set<BarcodeFormat> INDUSTRIAL_FORMATS;
  5. // private static final Set<BarcodeFormat> ONE_D_FORMATS;
  6. static final Set<BarcodeFormat> QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE);
  7. // static final Set<BarcodeFormat> DATA_MATRIX_FORMATS = EnumSet.of(BarcodeFormat.DATA_MATRIX);
  8. // static final Set<BarcodeFormat> AZTEC_FORMATS = EnumSet.of(BarcodeFormat.AZTEC);
  9. // static final Set<BarcodeFormat> PDF417_FORMATS = EnumSet.of(BarcodeFormat.PDF_417);
  10. /*static {
  11. PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A,
  12. BarcodeFormat.UPC_E,
  13. BarcodeFormat.EAN_13,
  14. BarcodeFormat.EAN_8,
  15. BarcodeFormat.RSS_14,
  16. BarcodeFormat.RSS_EXPANDED);
  17. INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39,
  18. BarcodeFormat.CODE_93,
  19. BarcodeFormat.CODE_128,
  20. BarcodeFormat.ITF,
  21. BarcodeFormat.CODABAR);
  22. ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS);
  23. ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS);
  24. }*/
  25. private static final Map<String,Set<BarcodeFormat>> FORMATS_FOR_MODE;
  26. static {
  27. FORMATS_FOR_MODE = new HashMap<>();
  28. // FORMATS_FOR_MODE.put(Intents.Scan.ONE_D_MODE, ONE_D_FORMATS);
  29. // FORMATS_FOR_MODE.put(Intents.Scan.PRODUCT_MODE, PRODUCT_FORMATS);
  30. FORMATS_FOR_MODE.put(Intents.Scan.QR_CODE_MODE, QR_CODE_FORMATS);
  31. // FORMATS_FOR_MODE.put(Intents.Scan.DATA_MATRIX_MODE, DATA_MATRIX_FORMATS);
  32. // FORMATS_FOR_MODE.put(Intents.Scan.AZTEC_MODE, AZTEC_FORMATS);
  33. // FORMATS_FOR_MODE.put(Intents.Scan.PDF417_MODE, PDF417_FORMATS);
  34. }
  35. private DecodeFormatManager() {}
  36. static Set<BarcodeFormat> parseDecodeFormats(Intent intent) {
  37. Iterable<String> scanFormats = null;
  38. CharSequence scanFormatsString = intent.getStringExtra(Intents.Scan.FORMATS);
  39. if (scanFormatsString != null) {
  40. scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString));
  41. }
  42. return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE));
  43. }
  44. static Set<BarcodeFormat> parseDecodeFormats(Uri inputUri) {
  45. List<String> formats = inputUri.getQueryParameters(Intents.Scan.FORMATS);
  46. if (formats != null && formats.size() == 1 && formats.get(0) != null){
  47. formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0)));
  48. }
  49. return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE));
  50. }
  51. private static Set<BarcodeFormat> parseDecodeFormats(Iterable<String> scanFormats, String decodeMode) {
  52. if (scanFormats != null) {
  53. Set<BarcodeFormat> formats = EnumSet.noneOf(BarcodeFormat.class);
  54. try {
  55. for (String format : scanFormats) {
  56. formats.add(BarcodeFormat.valueOf(format));
  57. }
  58. return formats;
  59. } catch (IllegalArgumentException iae) {
  60. // ignore it then
  61. }
  62. }
  63. if (decodeMode != null) {
  64. return FORMATS_FOR_MODE.get(decodeMode);
  65. }
  66. return null;
  67. }
  68. }
DecodeHandler.java
  1. final class DecodeHandler extends Handler {
  2. private static final String TAG = DecodeHandler.class.getSimpleName();
  3. public static boolean isWeakLight = false;
  4. private final CaptureActivity activity;
  5. private final MultiFormatReader multiFormatReader;
  6. private boolean running = true;
  7. private final IMResUtil mImResUtil;
  8. DecodeHandler(CaptureActivity activity, Map<DecodeHintType, Object> hints) {
  9. multiFormatReader = new MultiFormatReader();
  10. multiFormatReader.setHints(hints);
  11. this.activity = activity;
  12. mImResUtil = new IMResUtil(activity);
  13. }
  14. @Override
  15. public void handleMessage(Message message) {
  16. if (!running) {
  17. return;
  18. }
  19. int what = message.what;
  20. if (what == mImResUtil.getId("device_qrcode_decode")) {
  21. decode((byte[]) message.obj, message.arg1, message.arg2);
  22. } else if (what == mImResUtil.getId("device_qrcode_quit")) {
  23. isWeakLight = false;
  24. CaptureActivity.isLightOn = false;
  25. running = false;
  26. Looper.myLooper().quit();
  27. }
  28. }
  29. /**
  30. * Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
  31. * reuse the same reader objects from one decode to the next.
  32. *
  33. * @param data The YUV preview frame.
  34. * @param width The width of the preview frame.
  35. * @param height The height of the preview frame.
  36. */
  37. private void decode(byte[] data, int width, int height) {
  38. Log.i(TAG, "decode");
  39. //弱光檢測(cè)
  40. analysisColor(data,width,height);
  41. long start = System.currentTimeMillis();
  42. Result rawResult = null;
  43. PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, width, height);
  44. if (source != null) {
  45. BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
  46. try {
  47. rawResult = multiFormatReader.decodeWithState(bitmap);
  48. } catch (ReaderException re) {
  49. // continue
  50. } finally {
  51. multiFormatReader.reset();
  52. }
  53. }
  54. Handler handler = activity.getHandler();//拿到CaptureActivityHandler
  55. Log.d(TAG, "Found handler " + handler);
  56. if (rawResult != null) {
  57. // Don't log the barcode contents for security.
  58. long end = System.currentTimeMillis();
  59. Log.d(TAG, "Found barcode in " + (end - start) + " ms");
  60. if (handler != null) {
  61. //給CaptureActivityHandler發(fā)消息
  62. Message message = Message.obtain(handler, mImResUtil.getId("device_qrcode_decode_succeeded"), rawResult);
  63. Bundle bundle = new Bundle();
  64. bundleThumbnail(source, bundle);
  65. message.setData(bundle);
  66. message.sendToTarget();
  67. }
  68. } else {
  69. if (handler != null) {
  70. Message message = Message.obtain(handler, mImResUtil.getId("device_qrcode_decode_failed"));
  71. message.sendToTarget();
  72. }
  73. }
  74. }
  75. private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) {
  76. int[] pixels = source.renderThumbnail();
  77. int width = source.getThumbnailWidth();
  78. int height = source.getThumbnailHeight();
  79. Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888);
  80. ByteArrayOutputStream out = new ByteArrayOutputStream();
  81. bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);
  82. bundle.putByteArray(DecodeThread.BARCODE_BITMAP, out.toByteArray());
  83. bundle.putFloat(DecodeThread.BARCODE_SCALED_FACTOR, (float) width / source.getWidth());
  84. }
  85. private int[] decodeYUV420SP(byte[] yuv420sp, int width, int height) {
  86. final int frameSize = width * height;
  87. int rgb[] = new int[width * height];
  88. for (int j = 0, yp = 0; j < height; j++) {
  89. int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
  90. for (int i = 0; i < width; i++, yp++) {
  91. int y = (0xff & ((int) yuv420sp[yp])) - 16;
  92. if (y < 0) y = 0;
  93. if ((i & 1) == 0) {
  94. v = (0xff & yuv420sp[uvp++]) - 128;
  95. u = (0xff & yuv420sp[uvp++]) - 128;
  96. }
  97. int y1192 = 1192 * y;
  98. int r = (y1192 + 1634 * v);
  99. int g = (y1192 - 833 * v - 400 * u);
  100. int b = (y1192 + 2066 * u);
  101. if (r < 0) r = 0;
  102. else if (r > 262143) r = 262143;
  103. if (g < 0) g = 0;
  104. else if (g > 262143) g = 262143;
  105. if (b < 0) b = 0;
  106. else if (b > 262143) b = 262143;
  107. rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) &
  108. 0xff00) | ((b >> 10) & 0xff);
  109. }
  110. }
  111. return rgb;
  112. }
  113. private int getAverageColor(Bitmap bitmap) {
  114. int redBucket = 0;
  115. int greenBucket = 0;
  116. int blueBucket = 0;
  117. int pixelCount = 0;
  118. for (int y = 0; y < bitmap.getHeight(); y++) {
  119. for (int x = 0; x < bitmap.getWidth(); x++) {
  120. int c = bitmap.getPixel(x, y);
  121. pixelCount++;
  122. redBucket += Color.red(c);
  123. greenBucket += Color.green(c);
  124. blueBucket += Color.blue(c);
  125. }
  126. }
  127. int averageColor = Color.rgb(redBucket / pixelCount, greenBucket
  128. / pixelCount, blueBucket / pixelCount);
  129. return averageColor;
  130. }
  131. //分析預(yù)覽幀中圖片的arg 取平均值
  132. public void analysisColor(byte[] data, int width, int height) {
  133. int[] rgb = decodeYUV420SP(data, width / 8, height / 8);
  134. Bitmap bmp = Bitmap.createBitmap(rgb, width / 8, height / 8, Bitmap.Config.ARGB_8888);//這里報(bào)錯(cuò)
  135. if (bmp != null) {
  136. //取以中心點(diǎn)寬高10像素的圖片來分析
  137. Bitmap resizeBitmap = Bitmap.createBitmap(bmp, bmp.getWidth() / 2, bmp.getHeight() / 2, 10, 10);
  138. float color = (float) getAverageColor(resizeBitmap);
  139. DecimalFormat decimalFormat1 = new DecimalFormat("0.00");
  140. String percent = decimalFormat1.format(color / -16777216);
  141. float floatPercent = Float.parseFloat(percent);
  142. isWeakLight = floatPercent >= 0.99 && floatPercent <= 1.00;
  143. // Log.i(TAG,"isWeakLight "+isWeakLight);
  144. if (null != resizeBitmap) {
  145. resizeBitmap.recycle();
  146. }
  147. bmp.recycle();
  148. }
  149. }
  150. }
DecodeHintManager.java
  1. final class DecodeHintManager {
  2. private static final String TAG = DecodeHintManager.class.getSimpleName();
  3. // This pattern is used in decoding integer arrays.
  4. private static final Pattern COMMA = Pattern.compile(",");
  5. private DecodeHintManager() {}
  6. /**
  7. * <p>Split a query string into a list of name-value pairs.</p>
  8. *
  9. * <p>This is an alternative to the {@link Uri#getQueryParameterNames()} and
  10. * {@link Uri#getQueryParameters(String)}, which are quirky and not suitable
  11. * for exist-only Uri parameters.</p>
  12. *
  13. * <p>This method ignores multiple parameters with the same name and returns the
  14. * first one only. This is technically incorrect, but should be acceptable due
  15. * to the method of processing Hints: no multiple values for a hint.</p>
  16. *
  17. * @param query query to split
  18. * @return name-value pairs
  19. */
  20. private static Map<String,String> splitQuery(String query) {
  21. Map<String,String> map = new HashMap<>();
  22. int pos = 0;
  23. while (pos < query.length()) {
  24. if (query.charAt(pos) == '&') {
  25. // Skip consecutive ampersand separators.
  26. pos ++;
  27. continue;
  28. }
  29. int amp = query.indexOf('&', pos);
  30. int equ = query.indexOf('=', pos);
  31. if (amp < 0) {
  32. // This is the last element in the query, no more ampersand elements.
  33. String name;
  34. String text;
  35. if (equ < 0) {
  36. // No equal sign
  37. name = query.substring(pos);
  38. name = name.replace('+', ' '); // Preemptively decode +
  39. name = Uri.decode(name);
  40. text = "";
  41. } else {
  42. // Split name and text.
  43. name = query.substring(pos, equ);
  44. name = name.replace('+', ' '); // Preemptively decode +
  45. name = Uri.decode(name);
  46. text = query.substring(equ + 1);
  47. text = text.replace('+', ' '); // Preemptively decode +
  48. text = Uri.decode(text);
  49. }
  50. if (!map.containsKey(name)) {
  51. map.put(name, text);
  52. }
  53. break;
  54. }
  55. if (equ < 0 || equ > amp) {
  56. // No equal sign until the &: this is a simple parameter with no value.
  57. String name = query.substring(pos, amp);
  58. name = name.replace('+', ' '); // Preemptively decode +
  59. name = Uri.decode(name);
  60. if (!map.containsKey(name)) {
  61. map.put(name, "");
  62. }
  63. pos = amp + 1;
  64. continue;
  65. }
  66. String name = query.substring(pos, equ);
  67. name = name.replace('+', ' '); // Preemptively decode +
  68. name = Uri.decode(name);
  69. String text = query.substring(equ+1, amp);
  70. text = text.replace('+', ' '); // Preemptively decode +
  71. text = Uri.decode(text);
  72. if (!map.containsKey(name)) {
  73. map.put(name, text);
  74. }
  75. pos = amp + 1;
  76. }
  77. return map;
  78. }
  79. static Map<DecodeHintType,?> parseDecodeHints(Uri inputUri) {
  80. String query = inputUri.getEncodedQuery();
  81. if (query == null || query.isEmpty()) {
  82. return null;
  83. }
  84. // Extract parameters
  85. Map<String, String> parameters = splitQuery(query);
  86. Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
  87. for (DecodeHintType hintType: DecodeHintType.values()) {
  88. if (hintType == DecodeHintType.CHARACTER_SET ||
  89. hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
  90. hintType == DecodeHintType.POSSIBLE_FORMATS) {
  91. continue; // This hint is specified in another way
  92. }
  93. String parameterName = hintType.name();
  94. String parameterText = parameters.get(parameterName);
  95. if (parameterText == null) {
  96. continue;
  97. }
  98. if (hintType.getValueType().equals(Object.class)) {
  99. // This is an unspecified type of hint content. Use the value as is.
  100. // TODO: Can we make a different assumption on this?
  101. hints.put(hintType, parameterText);
  102. continue;
  103. }
  104. if (hintType.getValueType().equals(Void.class)) {
  105. // Void hints are just flags: use the constant specified by DecodeHintType
  106. hints.put(hintType, Boolean.TRUE);
  107. continue;
  108. }
  109. if (hintType.getValueType().equals(String.class)) {
  110. // A string hint: use the decoded value.
  111. hints.put(hintType, parameterText);
  112. continue;
  113. }
  114. if (hintType.getValueType().equals(Boolean.class)) {
  115. // A boolean hint: a few values for false, everything else is true.
  116. // An empty parameter is simply a flag-style parameter, assuming true
  117. if (parameterText.isEmpty()) {
  118. hints.put(hintType, Boolean.TRUE);
  119. } else if ("0".equals(parameterText) ||
  120. "false".equalsIgnoreCase(parameterText) ||
  121. "no".equalsIgnoreCase(parameterText)) {
  122. hints.put(hintType, Boolean.FALSE);
  123. } else {
  124. hints.put(hintType, Boolean.TRUE);
  125. }
  126. continue;
  127. }
  128. if (hintType.getValueType().equals(int[].class)) {
  129. // An integer array. Used to specify valid lengths.
  130. // Strip a trailing comma as in Java style array initialisers.
  131. if (!parameterText.isEmpty() && parameterText.charAt(parameterText.length() - 1) == ',') {
  132. parameterText = parameterText.substring(0, parameterText.length() - 1);
  133. }
  134. String[] values = COMMA.split(parameterText);
  135. int[] array = new int[values.length];
  136. for (int i = 0; i < values.length; i++) {
  137. try {
  138. array[i] = Integer.parseInt(values[i]);
  139. } catch (NumberFormatException ignored) {
  140. Log.w(TAG, "Skipping array of integers hint " + hintType + " due to invalid numeric value: '" + values[i] + '\'');
  141. array = null;
  142. break;
  143. }
  144. }
  145. if (array != null) {
  146. hints.put(hintType, array);
  147. }
  148. continue;
  149. }
  150. Log.w(TAG, "Unsupported hint type '" + hintType + "' of type " + hintType.getValueType());
  151. }
  152. Log.i(TAG, "Hints from the URI: " + hints);
  153. return hints;
  154. }
  155. static Map<DecodeHintType, Object> parseDecodeHints(Intent intent) {
  156. Bundle extras = intent.getExtras();
  157. if (extras == null || extras.isEmpty()) {
  158. return null;
  159. }
  160. Map<DecodeHintType,Object> hints = new EnumMap<>(DecodeHintType.class);
  161. for (DecodeHintType hintType: DecodeHintType.values()) {
  162. if (hintType == DecodeHintType.CHARACTER_SET ||
  163. hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
  164. hintType == DecodeHintType.POSSIBLE_FORMATS) {
  165. continue; // This hint is specified in another way
  166. }
  167. String hintName = hintType.name();
  168. if (extras.containsKey(hintName)) {
  169. if (hintType.getValueType().equals(Void.class)) {
  170. // Void hints are just flags: use the constant specified by the DecodeHintType
  171. hints.put(hintType, Boolean.TRUE);
  172. } else {
  173. Object hintData = extras.get(hintName);
  174. if (hintType.getValueType().isInstance(hintData)) {
  175. hints.put(hintType, hintData);
  176. } else {
  177. Log.w(TAG, "Ignoring hint " + hintType + " because it is not assignable from " + hintData);
  178. }
  179. }
  180. }
  181. }
  182. Log.i(TAG, "Hints from the Intent: " + hints);
  183. return hints;
  184. }
  185. }
DecodeThread.java
  1. final class DecodeThread extends Thread {
  2. public static final String BARCODE_BITMAP = "barcode_bitmap";
  3. public static final String BARCODE_SCALED_FACTOR = "barcode_scaled_factor";
  4. private final CaptureActivity activity;
  5. private final Map<DecodeHintType, Object> hints;
  6. private Handler handler;
  7. private final CountDownLatch handlerInitLatch;
  8. public DecodeThread(CaptureActivity activity,
  9. Collection<BarcodeFormat> decodeFormats,
  10. String characterSet,
  11. ResultPointCallback resultPointCallback) {
  12. this.activity = activity;
  13. handlerInitLatch = new CountDownLatch(1);
  14. hints = new EnumMap<>(DecodeHintType.class);
  15. // The prefs can't change while the thread is running, so pick them up once here.
  16. if (decodeFormats == null || decodeFormats.isEmpty()) {
  17. // SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
  18. decodeFormats = EnumSet.noneOf(BarcodeFormat.class);
  19. /*if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_1D_PRODUCT, true)) {
  20. decodeFormats.addAll(DecodeFormatManager.PRODUCT_FORMATS);
  21. }
  22. if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_1D_INDUSTRIAL, true)) {
  23. decodeFormats.addAll(DecodeFormatManager.INDUSTRIAL_FORMATS);
  24. }*/
  25. // if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_QR, true)) {
  26. decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
  27. // }
  28. /* if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_DATA_MATRIX, true)) {
  29. decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
  30. }
  31. if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_AZTEC, false)) {
  32. decodeFormats.addAll(DecodeFormatManager.AZTEC_FORMATS);
  33. }
  34. if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_PDF417, false)) {
  35. decodeFormats.addAll(DecodeFormatManager.PDF417_FORMATS);
  36. }*/
  37. }
  38. hints.put(DecodeHintType.POSSIBLE_FORMATS, DecodeFormatManager.QR_CODE_FORMATS);
  39. if (characterSet != null) {
  40. hints.put(DecodeHintType.CHARACTER_SET, characterSet);
  41. }
  42. hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback);
  43. Log.i("DecodeThread", "Hints: " + hints);
  44. }
  45. Handler getHandler() {
  46. try {
  47. handlerInitLatch.await();
  48. } catch (InterruptedException ie) {
  49. // continue?
  50. }
  51. return handler;
  52. }
  53. @Override
  54. public void run() {
  55. Looper.prepare();
  56. handler = new DecodeHandler(activity, hints);
  57. handlerInitLatch.countDown();
  58. Looper.loop();
  59. }
  60. }
ImageUtil.java
  1. public class ImageUtil {
  2. @TargetApi(19)
  3. public static String getImageAbsolutePath(Context context, Uri imageUri) {
  4. if (context == null || imageUri == null)
  5. return null;
  6. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, imageUri)) {
  7. if (isExternalStorageDocument(imageUri)) {
  8. String docId = DocumentsContract.getDocumentId(imageUri);
  9. String[] split = docId.split(":");
  10. String type = split[0];
  11. if ("primary".equalsIgnoreCase(type)) {
  12. return Environment.getExternalStorageDirectory() + "/" + split[1];
  13. }
  14. } else if (isDownloadsDocument(imageUri)) {
  15. String id = DocumentsContract.getDocumentId(imageUri);
  16. Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
  17. return getDataColumn(context, contentUri, null, null);
  18. } else if (isMediaDocument(imageUri)) {
  19. String docId = DocumentsContract.getDocumentId(imageUri);
  20. String[] split = docId.split(":");
  21. String type = split[0];
  22. Uri contentUri = null;
  23. if ("image".equals(type)) {
  24. contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
  25. } else if ("video".equals(type)) {
  26. contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
  27. } else if ("audio".equals(type)) {
  28. contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  29. }
  30. String selection = MediaStore.Images.Media._ID + "=?";
  31. String[] selectionArgs = new String[]{split[1]};
  32. return getDataColumn(context, contentUri, selection, selectionArgs);
  33. }
  34. } // MediaStore (and general)
  35. else if ("content".equalsIgnoreCase(imageUri.getScheme())) {
  36. // Return the remote address
  37. if (isGooglePhotosUri(imageUri))
  38. return imageUri.getLastPathSegment();
  39. return getDataColumn(context, imageUri, null, null);
  40. }
  41. // File
  42. else if ("file".equalsIgnoreCase(imageUri.getScheme())) {
  43. return imageUri.getPath();
  44. }
  45. return null;
  46. }
  47. public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
  48. Cursor cursor = null;
  49. String column = MediaStore.Images.Media.DATA;
  50. String[] projection = {column};
  51. try {
  52. cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
  53. if (cursor != null && cursor.moveToFirst()) {
  54. int index = cursor.getColumnIndexOrThrow(column);
  55. return cursor.getString(index);
  56. }
  57. } finally {
  58. if (cursor != null)
  59. cursor.close();
  60. }
  61. return null;
  62. }
  63. /**
  64. * @param uri The Uri to check.
  65. * @return Whether the Uri authority is ExternalStorageProvider.
  66. */
  67. public static boolean isExternalStorageDocument(Uri uri) {
  68. return "com.android.externalstorage.documents".equals(uri.getAuthority());
  69. }
  70. /**
  71. * @param uri The Uri to check.
  72. * @return Whether the Uri authority is DownloadsProvider.
  73. */
  74. public static boolean isDownloadsDocument(Uri uri) {
  75. return "com.android.providers.downloads.documents".equals(uri.getAuthority());
  76. }
  77. /**
  78. * @param uri The Uri to check.
  79. * @return Whether the Uri authority is MediaProvider.
  80. */
  81. public static boolean isMediaDocument(Uri uri) {
  82. return "com.android.providers.media.documents".equals(uri.getAuthority());
  83. }
  84. /**
  85. * @param uri The Uri to check.
  86. * @return Whether the Uri authority is Google Photos.
  87. */
  88. public static boolean isGooglePhotosUri(Uri uri) {
  89. return "com.google.android.apps.photos.content".equals(uri.getAuthority());
  90. }
  91. }
InactivityTimer.java
  1. public final class InactivityTimer {
  2. private static final String TAG = InactivityTimer.class.getSimpleName();
  3. private static final long INACTIVITY_DELAY_MS = 5 * 60 * 1000L;
  4. private final Activity activity;
  5. private final BroadcastReceiver powerStatusReceiver;
  6. private boolean registered;
  7. private AsyncTask<Object, Object, Object> inactivityTask;
  8. public InactivityTimer(Activity activity) {
  9. this.activity = activity;
  10. powerStatusReceiver = new PowerStatusReceiver();
  11. registered = false;
  12. onActivity();
  13. }
  14. public synchronized void onActivity() {
  15. cancel();
  16. inactivityTask = new InactivityAsyncTask();
  17. inactivityTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  18. }
  19. public synchronized void onPause() {
  20. cancel();
  21. if (registered) {
  22. activity.unregisterReceiver(powerStatusReceiver);
  23. registered = false;
  24. } else {
  25. Log.w(TAG, "PowerStatusReceiver was never registered?");
  26. }
  27. }
  28. public synchronized void onResume() {
  29. if (registered) {
  30. Log.w(TAG, "PowerStatusReceiver was already registered?");
  31. } else {
  32. activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
  33. registered = true;
  34. }
  35. onActivity();
  36. }
  37. private synchronized void cancel() {
  38. AsyncTask<?, ?, ?> task = inactivityTask;
  39. if (task != null) {
  40. task.cancel(true);
  41. inactivityTask = null;
  42. }
  43. }
  44. public void shutdown() {
  45. cancel();
  46. }
  47. private final class PowerStatusReceiver extends BroadcastReceiver {
  48. @Override
  49. public void onReceive(Context context, Intent intent) {
  50. if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
  51. // 0 indicates that we're on battery
  52. boolean onBatteryNow = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) <= 0;
  53. if (onBatteryNow) {
  54. InactivityTimer.this.onActivity();
  55. } else {
  56. InactivityTimer.this.cancel();
  57. }
  58. }
  59. }
  60. }
  61. private final class InactivityAsyncTask extends AsyncTask<Object, Object, Object> {
  62. @Override
  63. protected Object doInBackground(Object... objects) {
  64. try {
  65. Thread.sleep(INACTIVITY_DELAY_MS);
  66. Log.i(TAG, "Finishing activity due to inactivity");
  67. activity.finish();
  68. } catch (InterruptedException e) {
  69. // continue without killing
  70. }
  71. return null;
  72. }
  73. }
  74. }
Intents.java
  1. public final class Intents {
  2. private Intents() {
  3. }
  4. public static final class Scan {
  5. /**
  6. * Send this intent to open the Barcodes app in scanning mode, find a barcode, and return
  7. * the results.
  8. */
  9. public static final String ACTION = "com.google.zxing.client.android.SCAN";
  10. /**
  11. * By default, sending this will decode all barcodes that we understand. However it
  12. * may be useful to limit scanning to certain formats. Use
  13. * {@link android.content.Intent#putExtra(String, String)} with one of the values below.
  14. *
  15. * Setting this is effectively shorthand for setting explicit formats with {@link #FORMATS}.
  16. * It is overridden by that setting.
  17. */
  18. public static final String MODE = "SCAN_MODE";
  19. /**
  20. * Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get
  21. * prices, reviews, etc. for products.
  22. */
  23. public static final String PRODUCT_MODE = "PRODUCT_MODE";
  24. /**
  25. * Decode only 1D barcodes.
  26. */
  27. public static final String ONE_D_MODE = "ONE_D_MODE";
  28. /**
  29. * Decode only QR codes.
  30. */
  31. public static final String QR_CODE_MODE = "QR_CODE_MODE";
  32. /**
  33. * Decode only Data Matrix codes.
  34. */
  35. public static final String DATA_MATRIX_MODE = "DATA_MATRIX_MODE";
  36. /**
  37. * Decode only Aztec.
  38. */
  39. public static final String AZTEC_MODE = "AZTEC_MODE";
  40. /**
  41. * Decode only PDF417.
  42. */
  43. public static final String PDF417_MODE = "PDF417_MODE";
  44. /**
  45. * Comma-separated list of formats to scan for. The values must match the names of
  46. * {@link com.google.zxing.BarcodeFormat}s, e.g. {@link com.google.zxing.BarcodeFormat#EAN_13}.
  47. * Example: "EAN_13,EAN_8,QR_CODE". This overrides {@link #MODE}.
  48. */
  49. public static final String FORMATS = "SCAN_FORMATS";
  50. /**
  51. * Optional parameter to specify the id of the camera from which to recognize barcodes.
  52. * Overrides the default camera that would otherwise would have been selected.
  53. * If provided, should be an int.
  54. */
  55. public static final String CAMERA_ID = "SCAN_CAMERA_ID";
  56. /**
  57. * @see com.google.zxing.DecodeHintType#CHARACTER_SET
  58. */
  59. public static final String CHARACTER_SET = "CHARACTER_SET";
  60. /**
  61. * Optional parameters to specify the width and height of the scanning rectangle in pixels.
  62. * The app will try to honor these, but will clamp them to the size of the preview frame.
  63. * You should specify both or neither, and pass the size as an int.
  64. */
  65. public static final String WIDTH = "SCAN_WIDTH";
  66. public static final String HEIGHT = "SCAN_HEIGHT";
  67. /**
  68. * Desired duration in milliseconds for which to pause after a successful scan before
  69. * returning to the calling intent. Specified as a long, not an integer!
  70. * For example: 1000L, not 1000.
  71. */
  72. public static final String RESULT_DISPLAY_DURATION_MS = "RESULT_DISPLAY_DURATION_MS";
  73. /**
  74. * Prompt to show on-screen when scanning by intent. Specified as a {@link String}.
  75. */
  76. public static final String PROMPT_MESSAGE = "PROMPT_MESSAGE";
  77. /**
  78. * If a barcode is found, Barcodes returns {@link android.app.Activity#RESULT_OK} to
  79. * {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)}
  80. * of the app which requested the scan via
  81. * {@link android.app.Activity#startActivityForResult(android.content.Intent, int)}
  82. * The barcodes contents can be retrieved with
  83. * {@link android.content.Intent#getStringExtra(String)}.
  84. * If the user presses Back, the result code will be {@link android.app.Activity#RESULT_CANCELED}.
  85. */
  86. public static final String RESULT = "SCAN_RESULT";
  87. /**
  88. * Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_FORMAT}
  89. * to determine which barcode format was found.
  90. * See {@link com.google.zxing.BarcodeFormat} for possible values.
  91. */
  92. public static final String RESULT_FORMAT = "SCAN_RESULT_FORMAT";
  93. /**
  94. * Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_UPC_EAN_EXTENSION}
  95. * to return the content of any UPC extension barcode that was also found. Only applicable
  96. * to {@link com.google.zxing.BarcodeFormat#UPC_A} and {@link com.google.zxing.BarcodeFormat#EAN_13}
  97. * formats.
  98. */
  99. public static final String RESULT_UPC_EAN_EXTENSION = "SCAN_RESULT_UPC_EAN_EXTENSION";
  100. /**
  101. * Call {@link android.content.Intent#getByteArrayExtra(String)} with {@link #RESULT_BYTES}
  102. * to get a {@code byte[]} of raw bytes in the barcode, if available.
  103. */
  104. public static final String RESULT_BYTES = "SCAN_RESULT_BYTES";
  105. /**
  106. * Key for the value of {@link com.google.zxing.ResultMetadataType#ORIENTATION}, if available.
  107. * Call {@link android.content.Intent#getIntArrayExtra(String)} with {@link #RESULT_ORIENTATION}.
  108. */
  109. public static final String RESULT_ORIENTATION = "SCAN_RESULT_ORIENTATION";
  110. /**
  111. * Key for the value of {@link com.google.zxing.ResultMetadataType#ERROR_CORRECTION_LEVEL}, if available.
  112. * Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_ERROR_CORRECTION_LEVEL}.
  113. */
  114. public static final String RESULT_ERROR_CORRECTION_LEVEL = "SCAN_RESULT_ERROR_CORRECTION_LEVEL";
  115. /**
  116. * Prefix for keys that map to the values of {@link com.google.zxing.ResultMetadataType#BYTE_SEGMENTS},
  117. * if available. The actual values will be set under a series of keys formed by adding 0, 1, 2, ...
  118. * to this prefix. So the first byte segment is under key "SCAN_RESULT_BYTE_SEGMENTS_0" for example.
  119. * Call {@link android.content.Intent#getByteArrayExtra(String)} with these keys.
  120. */
  121. public static final String RESULT_BYTE_SEGMENTS_PREFIX = "SCAN_RESULT_BYTE_SEGMENTS_";
  122. /**
  123. * Setting this to false will not save scanned codes in the history. Specified as a {@code boolean}.
  124. */
  125. public static final String SAVE_HISTORY = "SAVE_HISTORY";
  126. private Scan() {
  127. }
  128. }
  129. public static final class History {
  130. public static final String ITEM_NUMBER = "ITEM_NUMBER";
  131. private History() {
  132. }
  133. }
  134. public static final class Encode {
  135. /**
  136. * Send this intent to encode a piece of data as a QR code and display it full screen, so
  137. * that another person can scan the barcode from your screen.
  138. */
  139. public static final String ACTION = "com.google.zxing.client.android.ENCODE";
  140. /**
  141. * The data to encode. Use {@link android.content.Intent#putExtra(String, String)} or
  142. * {@link android.content.Intent#putExtra(String, android.os.Bundle)},
  143. * depending on the type and format specified. Non-QR Code formats should
  144. * just use a String here. For QR Code, see Contents for details.
  145. */
  146. public static final String DATA = "ENCODE_DATA";
  147. /**
  148. * The type of data being supplied if the format is QR Code. Use
  149. * {@link android.content.Intent#putExtra(String, String)} with one of {@link Contents.Type}.
  150. */
  151. public static final String TYPE = "ENCODE_TYPE";
  152. /**
  153. * The barcode format to be displayed. If this isn't specified or is blank,
  154. * it defaults to QR Code. Use {@link android.content.Intent#putExtra(String, String)}, where
  155. * format is one of {@link com.google.zxing.BarcodeFormat}.
  156. */
  157. public static final String FORMAT = "ENCODE_FORMAT";
  158. /**
  159. * Normally the contents of the barcode are displayed to the user in a TextView. Setting this
  160. * boolean to false will hide that TextView, showing only the encode barcode.
  161. */
  162. public static final String SHOW_CONTENTS = "ENCODE_SHOW_CONTENTS";
  163. private Encode() {
  164. }
  165. }
  166. public static final class SearchBookContents {
  167. /**
  168. * Use Google Book Search to search the contents of the book provided.
  169. */
  170. public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS";
  171. /**
  172. * The book to search, identified by ISBN number.
  173. */
  174. public static final String ISBN = "ISBN";
  175. /**
  176. * An optional field which is the text to search for.
  177. */
  178. public static final String QUERY = "QUERY";
  179. private SearchBookContents() {
  180. }
  181. }
  182. public static final class WifiConnect {
  183. /**
  184. * Internal intent used to trigger connection to a wi-fi network.
  185. */
  186. public static final String ACTION = "com.google.zxing.client.android.WIFI_CONNECT";
  187. /**
  188. * The network to connect to, all the configuration provided here.
  189. */
  190. public static final String SSID = "SSID";
  191. /**
  192. * The network to connect to, all the configuration provided here.
  193. */
  194. public static final String TYPE = "TYPE";
  195. /**
  196. * The network to connect to, all the configuration provided here.
  197. */
  198. public static final String PASSWORD = "PASSWORD";
  199. private WifiConnect() {
  200. }
  201. }
  202. public static final class Share {
  203. /**
  204. * Give the user a choice of items to encode as a barcode, then render it as a QR Code and
  205. * display onscreen for a friend to scan with their phone.
  206. */
  207. public static final String ACTION = "com.google.zxing.client.android.SHARE";
  208. private Share() {
  209. }
  210. }
  211. }
ViewfinderResultPointCallback.java
  1. final class ViewfinderResultPointCallback implements ResultPointCallback {
  2. private final ViewfinderView viewfinderView;
  3. ViewfinderResultPointCallback(ViewfinderView viewfinderView) {
  4. this.viewfinderView = viewfinderView;
  5. }
  6. @Override
  7. public void foundPossibleResultPoint(ResultPoint point) {
  8. viewfinderView.addPossibleResultPoint(point);
  9. }
  10. }
CodeCreator.java
  1. public class CodeCreator {
  2. /*logo*/
  3. private static Bitmap logoBitmap;
  4. /*生成二維碼*/
  5. public static Bitmap createQRCode(String content, int w, int h,Bitmap logo) throws WriterException {
  6. if (TextUtils.isEmpty(content)) {
  7. return null;
  8. }
  9. /*偏移量*/
  10. int offsetX = w / 2;
  11. int offsetY = h / 2;
  12. /*生成logo*/
  13. if (logo!=null){
  14. Matrix matrix = new Matrix();
  15. float scaleFactor = Math.min(w * 1.0f / 5 / logo.getWidth(), h * 1.0f / 5 /logo.getHeight());
  16. matrix.postScale(scaleFactor,scaleFactor);
  17. logoBitmap= Bitmap.createBitmap(logo, 0, 0, logo.getWidth(), logo.getHeight(), matrix, true);
  18. }
  19. /*如果log不為null,重新計(jì)算偏移量*/
  20. int logoW = 0;
  21. int logoH = 0;
  22. if (logoBitmap != null) {
  23. logoW = logoBitmap.getWidth();
  24. logoH = logoBitmap.getHeight();
  25. offsetX = (w - logoW) / 2;
  26. offsetY = (h - logoH) / 2;
  27. }
  28. /*指定為UTF-8*/
  29. Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
  30. hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
  31. //容錯(cuò)級(jí)別
  32. hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
  33. //設(shè)置空白邊距的寬度
  34. hints.put(EncodeHintType.MARGIN, 0);
  35. // 生成二維矩陣,編碼時(shí)指定大小,不要生成了圖片以后再進(jìn)行縮放,這樣會(huì)模糊導(dǎo)致識(shí)別失敗
  36. BitMatrix matrix = new MultiFormatWriter().encode(content,
  37. BarcodeFormat.QR_CODE, w, h, hints);
  38. // 二維矩陣轉(zhuǎn)為一維像素?cái)?shù)組,也就是一直橫著排了
  39. int[] pixels = new int[w * h];
  40. for (int y = 0; y < h; y++) {
  41. for (int x = 0; x < w; x++) {
  42. if(x >= offsetX && x < offsetX + logoW && y>= offsetY && y < offsetY + logoH){
  43. int pixel = logoBitmap.getPixel(x-offsetX,y-offsetY);
  44. if(pixel == 0){
  45. if(matrix.get(x, y)){
  46. pixel = 0xff000000;
  47. }else{
  48. pixel = 0xffffffff;
  49. }
  50. }
  51. pixels[y * w + x] = pixel;
  52. }else{
  53. if (matrix.get(x, y)) {
  54. pixels[y * w + x] = 0xff000000;
  55. } else {
  56. pixels[y * w + x] = 0xffffffff;
  57. }
  58. }
  59. }
  60. }
  61. Bitmap bitmap = Bitmap.createBitmap(w, h,
  62. Bitmap.Config.ARGB_8888);
  63. bitmap.setPixels(pixels, 0, w, 0, 0, w, h);
  64. return bitmap;
  65. }
  66. }
QRCodeEncoder.java
  1. public final class QRCodeEncoder {
  2. private static final String TAG = QRCodeEncoder.class.getSimpleName();
  3. private static final int WHITE = 0xFFFFFFFF;
  4. private static final int BLACK = 0xFF000000;
  5. public static Bitmap encodeAsBitmap(String contents, int dimension) throws WriterException {
  6. String contentsToEncode = contents;
  7. if (contentsToEncode == null) {
  8. return null;
  9. }
  10. Map<EncodeHintType, Object> hints = null;
  11. String encoding = guessAppropriateEncoding(contentsToEncode);
  12. if (encoding != null) {
  13. hints = new EnumMap<>(EncodeHintType.class);
  14. hints.put(EncodeHintType.CHARACTER_SET, encoding);
  15. }
  16. BitMatrix result;
  17. try {
  18. result = new MultiFormatWriter().encode(contentsToEncode, BarcodeFormat.QR_CODE, dimension, dimension, hints);
  19. } catch (IllegalArgumentException iae) {
  20. // Unsupported format
  21. return null;
  22. }
  23. int width = result.getWidth();
  24. int height = result.getHeight();
  25. int[] pixels = new int[width * height];
  26. for (int y = 0; y < height; y++) {
  27. int offset = y * width;
  28. for (int x = 0; x < width; x++) {
  29. pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
  30. }
  31. }
  32. Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
  33. bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
  34. return bitmap;
  35. }
  36. private static String guessAppropriateEncoding(CharSequence contents) {
  37. // Very crude at the moment
  38. for (int i = 0; i < contents.length(); i++) {
  39. if (contents.charAt(i) > 0xFF) {
  40. return "UTF-8";
  41. }
  42. }
  43. return null;
  44. }
  45. }
ViewfinderResultPointCallback.java
  1. public final class ViewfinderResultPointCallback implements ResultPointCallback {
  2. private final ViewfinderView viewfinderView;
  3. public ViewfinderResultPointCallback(ViewfinderView viewfinderView) {
  4. this.viewfinderView = viewfinderView;
  5. }
  6. @Override
  7. public void foundPossibleResultPoint(ResultPoint point) {
  8. viewfinderView.addPossibleResultPoint(point);
  9. }
  10. }
ViewfinderView.java
  1. public final class ViewfinderView extends View{
  2. private static final long ANIMATION_DELAY = 10;
  3. private static final int CORNER_RECT_HEIGHT = 40;
  4. private static final int CORNER_RECT_WIDTH = 8;
  5. private static final int OPAQUE = 255;
  6. private static final int[] SCANNER_ALPHA = new int[]{0, 64, 128, 192, OPAQUE, 192, 128, 64};
  7. private static final int SCANNER_LINE_HEIGHT = 10;
  8. private static final int SCANNER_LINE_MOVE_DISTANCE = 5;
  9. public static int scannerEnd = 0;
  10. public static int scannerStart = 0;
  11. private CameraManager cameraManager;
  12. private final int cornerColor;
  13. private final int frameColor;
  14. private String labelText;
  15. private int labelTextColor;
  16. private float labelTextSize;
  17. private final int laserColor;
  18. private Collection<ResultPoint> lastPossibleResultPoints;
  19. private final IMResUtil mImResUtil;
  20. private final int maskColor;
  21. private final Paint paint = new Paint();
  22. private Collection<ResultPoint> possibleResultPoints;
  23. private Bitmap resultBitmap;
  24. private final int resultColor;
  25. private final int resultPointColor;
  26. private int scannerAlpha;
  27. public ViewfinderView(Context context, AttributeSet attrs) {
  28. super(context, attrs);
  29. this.mImResUtil = new IMResUtil(context);
  30. TypedArray array = context.obtainStyledAttributes(attrs, this.mImResUtil.getStyleableArray("ViewfinderView"));
  31. this.laserColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_laser_color"), 65280);
  32. this.cornerColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_corner_color"), 65280);
  33. this.frameColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_frame_color"), 16777215);
  34. this.resultPointColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_result_point_color"), -1056964864);
  35. this.maskColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_mask_color"), 1610612736);
  36. this.resultColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_result_color"), -1342177280);
  37. this.labelTextColor = array.getColor(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_label_text_color"), -1862270977);
  38. this.labelText = array.getString(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_label_text"));
  39. this.labelTextSize = (float) array.getDimensionPixelSize(this.mImResUtil.getStyleable("ViewfinderView_device_qrcode_label_text_size"), (int) TypedValue.applyDimension(2, 16.0f, getResources().getDisplayMetrics()));
  40. this.paint.setAntiAlias(true);
  41. this.scannerAlpha = 0;
  42. this.possibleResultPoints = new HashSet(5);
  43. }
  44. public void setCameraManager(CameraManager cameraManager) {
  45. this.cameraManager = cameraManager;
  46. }
  47. public void onDraw(Canvas canvas) {
  48. Rect frame = this.cameraManager.getFramingRect();
  49. if (frame != null) {
  50. if (scannerStart == 0 || scannerEnd == 0) {
  51. scannerStart = frame.top;
  52. scannerEnd = frame.bottom;
  53. }
  54. drawExterior(canvas, frame, canvas.getWidth(), canvas.getHeight());
  55. if (this.resultBitmap != null) {
  56. this.paint.setAlpha(OPAQUE);
  57. canvas.drawBitmap(this.resultBitmap, (float) frame.left, (float) frame.top, this.paint);
  58. return;
  59. }
  60. drawFrame(canvas, frame);
  61. drawCorner(canvas, frame);
  62. drawLaserScanner(canvas, frame);
  63. drawTextInfo(canvas, frame);
  64. Collection<ResultPoint> currentPossible = this.possibleResultPoints;
  65. Collection<ResultPoint> currentLast = this.lastPossibleResultPoints;
  66. if (currentPossible.isEmpty()) {
  67. this.lastPossibleResultPoints = null;
  68. } else {
  69. this.possibleResultPoints = new HashSet(5);
  70. this.lastPossibleResultPoints = currentPossible;
  71. this.paint.setAlpha(OPAQUE);
  72. this.paint.setColor(this.resultPointColor);
  73. for (ResultPoint point : currentPossible) {
  74. canvas.drawCircle(((float) frame.left) + point.getX(), ((float) frame.top) + point.getY(), 6.0f, this.paint);
  75. }
  76. }
  77. if (currentLast != null) {
  78. this.paint.setAlpha(127);
  79. this.paint.setColor(this.resultPointColor);
  80. for (ResultPoint point2 : currentLast) {
  81. canvas.drawCircle(((float) frame.left) + point2.getX(), ((float) frame.top) + point2.getY(), 3.0f, this.paint);
  82. }
  83. }
  84. postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);
  85. }
  86. }
  87. private void drawTextInfo(Canvas canvas, Rect frame) {
  88. this.paint.setColor(this.labelTextColor);
  89. this.paint.setTextSize(TypedValue.applyDimension(2, this.labelTextSize, getResources().getDisplayMetrics()));
  90. this.paint.setTextAlign(Align.CENTER);
  91. }
  92. private void drawCorner(Canvas canvas, Rect frame) {
  93. this.paint.setColor(this.cornerColor);
  94. canvas.drawRect((float) frame.left, (float) frame.top, (float) (frame.left + CORNER_RECT_WIDTH), (float) (frame.top + CORNER_RECT_HEIGHT), this.paint);
  95. canvas.drawRect((float) frame.left, (float) frame.top, (float) (frame.left + CORNER_RECT_HEIGHT), (float) (frame.top + CORNER_RECT_WIDTH), this.paint);
  96. canvas.drawRect((float) (frame.right - 8), (float) frame.top, (float) frame.right, (float) (frame.top + CORNER_RECT_HEIGHT), this.paint);
  97. canvas.drawRect((float) (frame.right - 40), (float) frame.top, (float) frame.right, (float) (frame.top + CORNER_RECT_WIDTH), this.paint);
  98. canvas.drawRect((float) frame.left, (float) (frame.bottom - 8), (float) (frame.left + CORNER_RECT_HEIGHT), (float) frame.bottom, this.paint);
  99. canvas.drawRect((float) frame.left, (float) (frame.bottom - 40), (float) (frame.left + CORNER_RECT_WIDTH), (float) frame.bottom, this.paint);
  100. canvas.drawRect((float) (frame.right - 8), (float) (frame.bottom - 40), (float) frame.right, (float) frame.bottom, this.paint);
  101. canvas.drawRect((float) (frame.right - 40), (float) (frame.bottom - 8), (float) frame.right, (float) frame.bottom, this.paint);
  102. }
  103. private void drawLaserScanner(Canvas canvas, Rect frame) {
  104. this.paint.setColor(this.laserColor);
  105. LinearGradient linearGradient = new LinearGradient((float) frame.left, (float) scannerStart, (float) frame.left, (float) (scannerStart + 10), shadeColor(this.laserColor), this.laserColor, TileMode.MIRROR);
  106. RadialGradient radialGradient = new RadialGradient((float) (frame.left + (frame.width() / 2)), (float) (scannerStart + 5), 360.0f, this.laserColor, shadeColor(this.laserColor), TileMode.MIRROR);
  107. SweepGradient sweepGradient = new SweepGradient((float) (frame.left + (frame.width() / 2)), (float) (scannerStart + 10), shadeColor(this.laserColor), this.laserColor);
  108. ComposeShader composeShader = new ComposeShader(radialGradient, linearGradient, Mode.ADD);
  109. this.paint.setShader(radialGradient);
  110. if (scannerStart <= scannerEnd) {
  111. canvas.drawOval(new RectF((float) (frame.left + 20), (float) scannerStart, (float) (frame.right - 20), (float) (scannerStart + 10)), this.paint);
  112. scannerStart += 5;
  113. } else {
  114. scannerStart = frame.top;
  115. }
  116. this.paint.setShader(null);
  117. }
  118. public int shadeColor(int color) {
  119. return Integer.valueOf("20" + Integer.toHexString(color).substring(2), 16).intValue();
  120. }
  121. private void drawFrame(Canvas canvas, Rect frame) {
  122. this.paint.setColor(this.frameColor);
  123. canvas.drawRect((float) frame.left, (float) frame.top, (float) (frame.right + 1), (float) (frame.top + 2), this.paint);
  124. canvas.drawRect((float) frame.left, (float) (frame.top + 2), (float) (frame.left + 2), (float) (frame.bottom - 1), this.paint);
  125. canvas.drawRect((float) (frame.right - 1), (float) frame.top, (float) (frame.right + 1), (float) (frame.bottom - 1), this.paint);
  126. canvas.drawRect((float) frame.left, (float) (frame.bottom - 1), (float) (frame.right + 1), (float) (frame.bottom + 1), this.paint);
  127. }
  128. private void drawExterior(Canvas canvas, Rect frame, int width, int height) {
  129. this.paint.setColor(this.resultBitmap != null ? this.resultColor : this.maskColor);
  130. canvas.drawRect(0.0f, 0.0f, (float) width, (float) frame.top, this.paint);
  131. canvas.drawRect(0.0f, (float) frame.top, (float) frame.left, (float) (frame.bottom + 1), this.paint);
  132. canvas.drawRect((float) (frame.right + 1), (float) frame.top, (float) width, (float) (frame.bottom + 1), this.paint);
  133. canvas.drawRect(0.0f, (float) (frame.bottom + 1), (float) width, (float) height, this.paint);
  134. }
  135. public void drawViewfinder() {
  136. this.resultBitmap = null;
  137. invalidate();
  138. }
  139. public void drawResultBitmap(Bitmap barcode) {
  140. this.resultBitmap = barcode;
  141. invalidate();
  142. }
  143. public void addPossibleResultPoint(ResultPoint point) {
  144. this.possibleResultPoints.add(point);
  145. }
  146. public void setLabelText(String labelText) {
  147. this.labelText = labelText;
  148. }
  149. public void setLabelTextColor(int labelTextColor) {
  150. this.labelTextColor = labelTextColor;
  151. }
  152. public void setLabelTextSize(float labelTextSize) {
  153. this.labelTextSize = labelTextSize;
  154. }
  155. }
FileUtil.java
  1. public class FileUtil {
  2. private static String TAG = "FileUtil";
  3. public static String randomFileName(String ext) {
  4. return Long.toString(System.currentTimeMillis()) + ext;
  5. }
  6. public static boolean deleteFile(String name) {
  7. File file = new File(name);
  8. if (file.exists()) {
  9. return file.delete();
  10. }
  11. return false;
  12. }
  13. @SuppressWarnings("deprecation")
  14. public static String rotateAndSaveBitmap(File file, int outW, int outH, String outPath, Bitmap.CompressFormat format, int quality) {
  15. int originW;
  16. int originH;
  17. int orientation = ExifInterface.ORIENTATION_NORMAL;
  18. try {
  19. ExifInterface exif = new ExifInterface(file.getAbsolutePath());
  20. orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
  21. int w = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0);
  22. int h = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0);
  23. switch (orientation) {
  24. case ExifInterface.ORIENTATION_UNDEFINED:
  25. return null;
  26. case ExifInterface.ORIENTATION_ROTATE_90:
  27. case ExifInterface.ORIENTATION_ROTATE_270:
  28. originW = h;
  29. originH = w;
  30. break;
  31. default:
  32. originW = w;
  33. originH = h;
  34. break;
  35. }
  36. } catch (Exception e) {
  37. return null;
  38. }
  39. // boost decode bitmap performance
  40. int sampleSize;
  41. if (outW <= 0 && outH <= 0) {
  42. sampleSize = 1;
  43. outW = originW;
  44. outH = originH;
  45. } else if (outW <= 0 || outH <= 0) {
  46. if (outW <= 0) {
  47. sampleSize = originH / outH;
  48. outW = (int) (originW * (outH / (float) originH));
  49. } else {
  50. sampleSize = originW / outW;
  51. outH = (int) (originH * (outW / (float) originW));
  52. }
  53. } else {
  54. sampleSize = Math.min(originW / outW, originH / outH);
  55. }
  56. BitmapFactory.Options bmOptions = new BitmapFactory.Options();
  57. bmOptions.inJustDecodeBounds = false;
  58. bmOptions.inSampleSize = sampleSize;
  59. bmOptions.inPurgeable = true;
  60. Bitmap bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), bmOptions);
  61. float scaleX = outW;
  62. float scaleY = outH;
  63. Matrix matrix = new Matrix();
  64. switch (orientation) {
  65. case ExifInterface.ORIENTATION_NORMAL:
  66. scaleX /= bmp.getWidth();
  67. scaleY /= bmp.getHeight();
  68. matrix.postScale(scaleX, scaleY);
  69. break;
  70. case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
  71. scaleX /= bmp.getWidth();
  72. scaleY /= bmp.getHeight();
  73. matrix.setScale(-1, 1);
  74. matrix.postScale(scaleX, scaleY);
  75. break;
  76. case ExifInterface.ORIENTATION_ROTATE_180:
  77. scaleX /= bmp.getWidth();
  78. scaleY /= bmp.getHeight();
  79. matrix.setRotate(180);
  80. matrix.postScale(scaleX, scaleY);
  81. break;
  82. case ExifInterface.ORIENTATION_FLIP_VERTICAL:
  83. scaleX /= bmp.getWidth();
  84. scaleY /= bmp.getHeight();
  85. matrix.setRotate(180);
  86. matrix.postScale(-1, 1);
  87. matrix.postScale(scaleX, scaleY);
  88. break;
  89. case ExifInterface.ORIENTATION_TRANSPOSE:
  90. scaleX /= bmp.getWidth();
  91. scaleY /= bmp.getHeight();
  92. matrix.setRotate(90);
  93. matrix.postScale(-1, 1);
  94. matrix.postScale(scaleX, scaleY);
  95. break;
  96. case ExifInterface.ORIENTATION_ROTATE_90:
  97. scaleX /= bmp.getHeight();
  98. scaleY /= bmp.getWidth();
  99. matrix.setRotate(90);
  100. matrix.postScale(scaleX, scaleY);
  101. break;
  102. case ExifInterface.ORIENTATION_TRANSVERSE:
  103. scaleX /= bmp.getWidth();
  104. scaleY /= bmp.getHeight();
  105. matrix.setRotate(-90);
  106. matrix.postScale(-1, 1);
  107. matrix.postScale(scaleX, scaleY);
  108. break;
  109. case ExifInterface.ORIENTATION_ROTATE_270:
  110. scaleX /= bmp.getHeight();
  111. scaleY /= bmp.getWidth();
  112. matrix.setRotate(-90);
  113. matrix.postScale(scaleX, scaleY);
  114. break;
  115. default:
  116. break;
  117. }
  118. Bitmap bmpNew = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
  119. String newFile = bmp2File(bmpNew, outPath, format, quality);
  120. bmpNew.recycle();
  121. return newFile;
  122. }
  123. private static Point getBitmapSize(String file) {
  124. BitmapFactory.Options bmOptions = new BitmapFactory.Options();
  125. bmOptions.inJustDecodeBounds = true;
  126. BitmapFactory.decodeFile(file, bmOptions);
  127. int originW = bmOptions.outWidth;
  128. int originH = bmOptions.outHeight;
  129. return new Point(originW, originH);
  130. }
  131. @SuppressWarnings("deprecation")
  132. public static String saveBitmap(File f, int outW, int outH, String outPath, Bitmap.CompressFormat format, int quality) {
  133. String rotateFile = rotateAndSaveBitmap(f, outW, outH, outPath, format, quality);
  134. if (null != rotateFile)
  135. return rotateFile;
  136. if (f == null) return "";
  137. String file = f.getAbsolutePath();
  138. // Get the dimensions of the bitmap
  139. Point size = getBitmapSize(file);
  140. int originW = size.x;
  141. int originH = size.y;
  142. // Determine how much to scale down the image
  143. int scaleFactor;
  144. if (outW <= 0 && outH <= 0) {
  145. scaleFactor = 1;
  146. outW = originW;
  147. outH = originH;
  148. } else if (outW <= 0 || outH <= 0) {
  149. if (outW <= 0) {
  150. scaleFactor = originH / outH;
  151. outW = (int) (originW * (outH / (float) originH));
  152. } else {
  153. scaleFactor = originW / outW;
  154. outH = (int) (originH * (outW / (float) originW));
  155. }
  156. } else {
  157. scaleFactor = Math.min(originW / outW, originH / outH);
  158. }
  159. // Decode the image file into a Bitmap sized to fit out size
  160. BitmapFactory.Options bmOptions = new BitmapFactory.Options();
  161. bmOptions.inJustDecodeBounds = false;
  162. bmOptions.inSampleSize = scaleFactor;
  163. bmOptions.inPurgeable = true;
  164. Bitmap bmp = BitmapFactory.decodeFile(file, bmOptions);
  165. String newFile;
  166. if (bmp == null) {
  167. return "";
  168. }
  169. if (bmp.getWidth() != outW && bmp.getHeight() != outH) {
  170. Bitmap bmpNew = Bitmap.createScaledBitmap(bmp, outW, outH, true);
  171. newFile = bmp2File(bmpNew, outPath, format, quality);
  172. bmpNew.recycle();
  173. } else {
  174. newFile = bmp2File(bmp, outPath, format, quality);
  175. }
  176. bmp.recycle();
  177. return newFile;
  178. }
  179. public static Point calcScaleSize(String file, int outW, int outH) {
  180. int originW = 0;
  181. int originH = 0;
  182. try {
  183. ExifInterface exif = new ExifInterface(file);
  184. int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
  185. int w = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0);
  186. int h = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0);
  187. switch (orientation) {
  188. case ExifInterface.ORIENTATION_UNDEFINED:
  189. break;
  190. case ExifInterface.ORIENTATION_ROTATE_90:
  191. case ExifInterface.ORIENTATION_ROTATE_270:
  192. originW = h;
  193. originH = w;
  194. break;
  195. default:
  196. originW = w;
  197. originH = h;
  198. break;
  199. }
  200. } catch (Exception e) {
  201. }
  202. if (0 == originW || 0 == originH) {
  203. Point size = getBitmapSize(file);
  204. originW = size.x;
  205. originH = size.y;
  206. }
  207. if (outW <= 0 && outH <= 0) {
  208. outW = originW;
  209. outH = originH;
  210. } else if (outW <= 0 || outH <= 0) {
  211. if (outW <= 0) {
  212. outW = (int) (originW * (outH / (float) originH));
  213. } else {
  214. outH = (int) (originH * (outW / (float) originW));
  215. }
  216. } else {
  217. }
  218. return new Point(outW, outH);
  219. }
  220. public static String bmp2File(Bitmap bmp, String filePath, Bitmap.CompressFormat format, int quality) {
  221. String fileName = FileUtil.randomFileName(Bitmap.CompressFormat.PNG == format ? ".png" : ".jpg");
  222. String fullPath = filePath + fileName;
  223. deleteFile(fileName);
  224. File file = new File(fullPath);
  225. try {
  226. file.createNewFile();
  227. } catch (IOException e) {
  228. e.printStackTrace();
  229. return null;
  230. }
  231. FileOutputStream fOut = null;
  232. try {
  233. fOut = new FileOutputStream(file);
  234. } catch (FileNotFoundException e) {
  235. e.printStackTrace();
  236. return null;
  237. }
  238. bmp.compress(format, quality, fOut);
  239. try {
  240. fOut.flush();
  241. fOut.close();
  242. fOut = null;
  243. } catch (IOException e) {
  244. e.printStackTrace();
  245. return null;
  246. } finally {
  247. try {
  248. if (null != fOut) {
  249. fOut.close();
  250. fOut = null;
  251. }
  252. } catch (Exception e) {
  253. e.printStackTrace();
  254. return null;
  255. }
  256. }
  257. return fileName;
  258. }
  259. public static final String insertImage(ContentResolver cr, String imagePath, String name, String description) throws FileNotFoundException {
  260. FileInputStream inStream = new FileInputStream(imagePath);
  261. return insertImage(cr, inStream, name, description);
  262. }
  263. /**
  264. * A copy of the Android internals insertImage method, this method populates
  265. * the meta data with DATE_ADDED and DATE_TAKEN. This fixes a common problem
  266. * where media that is inserted manually gets saved at the end of the
  267. * gallery (because date is not populated).
  268. *
  269. * @see Images.Media#insertImage(ContentResolver,
  270. * Bitmap, String, String)
  271. */
  272. public static final String insertImage(ContentResolver cr, FileInputStream inStream, String title, String description) {
  273. ContentValues values = new ContentValues();
  274. values.put(Images.Media.TITLE, title);
  275. values.put(Images.Media.DISPLAY_NAME, title);
  276. values.put(Images.Media.DESCRIPTION, description);
  277. values.put(Images.Media.MIME_TYPE, "image/jpeg");
  278. // Add the date meta data to ensure the image is added at the front of
  279. // the gallery
  280. values.put(Images.Media.DATE_ADDED, System.currentTimeMillis());
  281. values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis());
  282. Uri url = null;
  283. String stringUrl = null; /* value to be returned */
  284. try {
  285. url = cr.insert(Images.Media.EXTERNAL_CONTENT_URI, values);
  286. if (inStream != null) {
  287. OutputStream imageOut = cr.openOutputStream(url);
  288. byte[] buffer = new byte[1024];
  289. int count = 0;
  290. while ((count = inStream.read(buffer)) >= 0) {
  291. imageOut.write(buffer, 0, count);
  292. }
  293. imageOut.flush();
  294. inStream.close();
  295. long id = ContentUris.parseId(url);
  296. // Wait until MINI_KIND thumbnail is generated.
  297. Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id, Images.Thumbnails.MINI_KIND, null);
  298. // This is for backward compatibility.
  299. storeThumbnail(cr, miniThumb, id, 50F, 50F, Images.Thumbnails.MICRO_KIND);
  300. } else {
  301. cr.delete(url, null, null);
  302. url = null;
  303. }
  304. } catch (Exception e) {
  305. e.printStackTrace();
  306. if (url != null) {
  307. cr.delete(url, null, null);
  308. url = null;
  309. }
  310. }
  311. if (url != null) {
  312. stringUrl = url.toString();
  313. }
  314. return stringUrl;
  315. }
  316. /**
  317. * A copy of the Android internals StoreThumbnail method, it used with the
  318. * insertImage to populate the
  319. * android.provider.MediaStore.Images.Media#insertImage with all the correct
  320. * meta data. The StoreThumbnail method is private so it must be duplicated
  321. * here.
  322. *
  323. * @see Images.Media (StoreThumbnail private
  324. * method)
  325. */
  326. private static final Bitmap storeThumbnail(ContentResolver cr, Bitmap source, long id, float width, float height, int kind) {
  327. // create the matrix to scale it
  328. Matrix matrix = new Matrix();
  329. float scaleX = width / source.getWidth();
  330. float scaleY = height / source.getHeight();
  331. matrix.setScale(scaleX, scaleY);
  332. Bitmap thumb = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
  333. ContentValues values = new ContentValues(4);
  334. values.put(Images.Thumbnails.KIND, kind);
  335. values.put(Images.Thumbnails.IMAGE_ID, (int) id);
  336. values.put(Images.Thumbnails.HEIGHT, thumb.getHeight());
  337. values.put(Images.Thumbnails.WIDTH, thumb.getWidth());
  338. Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values);
  339. try {
  340. OutputStream thumbOut = cr.openOutputStream(url);
  341. thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);
  342. thumbOut.close();
  343. return thumb;
  344. } catch (FileNotFoundException ex) {
  345. return null;
  346. } catch (IOException ex) {
  347. return null;
  348. }
  349. }
  350. // /////////////////////////////////////////////////
  351. @SuppressLint("NewApi")
  352. public static String checkPicturePath(final Context context, final Uri uri) {
  353. final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
  354. // DocumentProvider
  355. if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
  356. // ExternalStorageProvider
  357. if (isExternalStorageDocument(uri)) {
  358. final String docId = DocumentsContract.getDocumentId(uri);
  359. final String[] split = docId.split(":");
  360. final String type = split[0];
  361. if ("primary".equalsIgnoreCase(type)) {
  362. return Environment.getExternalStorageDirectory() + "/" + split[1];
  363. }
  364. }
  365. // DownloadsProvider
  366. else if (isDownloadsDocument(uri)) {
  367. final String id = DocumentsContract.getDocumentId(uri);
  368. final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
  369. return getDataColumn(context, contentUri, null, null);
  370. }
  371. // MediaProvider
  372. else if (isMediaDocument(uri)) {
  373. final String docId = DocumentsContract.getDocumentId(uri);
  374. final String[] split = docId.split(":");
  375. final String type = split[0];
  376. Uri contentUri = null;
  377. if ("image".equals(type)) {
  378. contentUri = Images.Media.EXTERNAL_CONTENT_URI;
  379. } else if ("video".equals(type)) {
  380. contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
  381. } else if ("audio".equals(type)) {
  382. contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  383. }
  384. final String selection = "_id=?";
  385. final String[] selectionArgs = new String[]{split[1]};
  386. return getDataColumn(context, contentUri, selection, selectionArgs);
  387. }
  388. }
  389. // MediaStore (and general)
  390. else if ("content".equalsIgnoreCase(uri.getScheme())) {
  391. // Return the remote address
  392. if (isGooglePhotosUri(uri))
  393. return uri.getLastPathSegment();
  394. return getDataColumn(context, uri, null, null);
  395. }
  396. // File
  397. else if ("file".equalsIgnoreCase(uri.getScheme())) {
  398. return uri.getPath();
  399. }
  400. return null;
  401. }
  402. /**
  403. * Get the value of the data column for this Uri. This is useful for
  404. * MediaStore Uris, and other file-based ContentProviders.
  405. *
  406. * @param context The context.
  407. * @param uri The Uri to query.
  408. * @param selection (Optional) Filter used in the query.
  409. * @param selectionArgs (Optional) Selection arguments used in the query.
  410. * @return The value of the _data column, which is typically a file path.
  411. */
  412. private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
  413. Cursor cursor = null;
  414. final String column = "_data";
  415. final String[] projection = {column};
  416. try {
  417. cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
  418. if (cursor != null && cursor.moveToFirst()) {
  419. final int index = cursor.getColumnIndexOrThrow(column);
  420. return cursor.getString(index);
  421. }
  422. } catch (Exception e) {
  423. e.printStackTrace();
  424. } finally {
  425. if (cursor != null)
  426. cursor.close();
  427. }
  428. return null;
  429. }
  430. /**
  431. * @param uri The Uri to check.
  432. * @return Whether the Uri authority is ExternalStorageProvider.
  433. */
  434. private static boolean isExternalStorageDocument(Uri uri) {
  435. return "com.android.externalstorage.documents".equals(uri.getAuthority());
  436. }
  437. /**
  438. * @param uri The Uri to check.
  439. * @return Whether the Uri authority is DownloadsProvider.
  440. */
  441. private static boolean isDownloadsDocument(Uri uri) {
  442. return "com.android.providers.downloads.documents".equals(uri.getAuthority());
  443. }
  444. /**
  445. * @param uri The Uri to check.
  446. * @return Whether the Uri authority is MediaProvider.
  447. */
  448. private static boolean isMediaDocument(Uri uri) {
  449. return "com.android.providers.media.documents".equals(uri.getAuthority());
  450. }
  451. /**
  452. * @param uri The Uri to check.
  453. * @return Whether the Uri authority is Google Photos.
  454. */
  455. private static boolean isGooglePhotosUri(Uri uri) {
  456. return "com.google.android.apps.photos.content".equals(uri.getAuthority());
  457. }
  458. }
IMResUtil.java
  1. public class IMResUtil {
  2. private static final String TAG = "IMResUtil";
  3. private static IMResUtil instance;
  4. private Context context;
  5. private static Class id = null;
  6. private static Class layout = null;
  7. private static Class style = null;
  8. private static Class attr = null;
  9. private static Class styleable = null;
  10. public IMResUtil(Context paramContext) {
  11. this.context = paramContext.getApplicationContext();
  12. try {
  13. layout = Class.forName(this.context.getPackageName() + ".R$layout");
  14. } catch (ClassNotFoundException localClassNotFoundException2) {
  15. Log.e(TAG,"localClassNotFoundException2 = " + localClassNotFoundException2.toString());
  16. }
  17. try {
  18. id = Class.forName(this.context.getPackageName() + ".R$id");
  19. } catch (ClassNotFoundException localClassNotFoundException3) {
  20. Log.e(TAG,"localClassNotFoundException3 = " + localClassNotFoundException3.toString());
  21. }
  22. try {
  23. style = Class.forName(this.context.getPackageName() + ".R$style");
  24. } catch (ClassNotFoundException localClassNotFoundException5) {
  25. Log.e(TAG,"localClassNotFoundException5 = " + localClassNotFoundException5.toString());
  26. }
  27. try {
  28. attr = Class.forName(this.context.getPackageName() + ".R$attr");
  29. } catch (ClassNotFoundException localClassNotFoundException10) {
  30. Log.e(TAG,"localClassNotFoundException10 = " + localClassNotFoundException10.toString());
  31. }
  32. try {
  33. styleable = Class.forName(this.context.getPackageName() + ".R$styleable");
  34. } catch (ClassNotFoundException localClassNotFoundException10) {
  35. Log.e(TAG,"localClassNotFoundException10 = " + localClassNotFoundException10.toString());
  36. }
  37. }
  38. public static IMResUtil getResofR(Context paramContext) {
  39. if (instance == null)
  40. instance = new IMResUtil(paramContext);
  41. return instance;
  42. }
  43. public int getId(String paramString) {
  44. return getResofR(id, paramString);
  45. }
  46. public int getLayout(String paramString) {
  47. return getResofR(layout, paramString);
  48. }
  49. public int getStyle(String paramString) {
  50. return getResofR(style, paramString);
  51. }
  52. public int getAttr(String paramString) {return getResofR(attr, paramString);}
  53. public int getStyleable(String paramString) {return getResofR(styleable, paramString);}
  54. public int [] getStyleableArray(String paramString){
  55. try {
  56. Class clz = Class.forName(context.getPackageName()+".R$styleable");
  57. Field field = clz.getField(paramString);
  58. Object object = field.get(clz);
  59. int[] attr = (int[]) object;
  60. for (int i = 0; i < attr.length; i++) {
  61. Log.d(TAG, attr[i]+"");
  62. }
  63. return attr;
  64. } catch (Exception e) {
  65. Log.d(TAG, e.getMessage());
  66. e.printStackTrace();
  67. }
  68. return null;
  69. }
  70. private int getResofR(Class<?> paramClass, String paramString) {
  71. if (paramClass == null) {
  72. Log.d(TAG,"getRes(null," + paramString + ")");
  73. Log.d(TAG,"Class is null ,ResClass is not initialized.");
  74. return -1;
  75. // throw new IllegalArgumentException("ResClass is not initialized.");
  76. }
  77. try {
  78. Field localField = paramClass.getField(paramString);
  79. int k = localField.getInt(paramString);
  80. return k;
  81. } catch (Exception localException) {
  82. Log.e(TAG,"getRes(" + paramClass.getName() + ", " + paramString + ")");
  83. Log.e(TAG,"Error getting resource. Make sure you have copied all resources (res/) from SDK to your project. ");
  84. Log.e(TAG,localException.getMessage());
  85. }
  86. return -1;
  87. }
  88. }

xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas./apk/res/android"
  3. xmlns:app="http://schemas./apk/res-auto"
  4. xmlns:tools="http://schemas./tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent">
  7. <!--抬頭部分-->
  8. <RelativeLayout
  9. android:id="@+id/rl"
  10. android:layout_width="fill_parent"
  11. android:layout_height="50dp"
  12. android:background="#000000"
  13. android:paddingLeft="6dp"
  14. android:paddingStart="6dp">
  15. <ImageView
  16. android:id="@+id/iv_qr_back"
  17. android:layout_width="30dp"
  18. android:layout_height="24dp"
  19. android:layout_centerVertical="true"
  20. android:src="@drawable/arrow_back"/>
  21. <TextView
  22. android:id="@+id/tv_qr_title"
  23. android:layout_width="wrap_content"
  24. android:layout_height="match_parent"
  25. android:layout_centerHorizontal="true"
  26. android:clickable="true"
  27. android:focusable="true"
  28. android:gravity="center"
  29. android:textColor="#ffffff"
  30. android:textSize="20sp"/>
  31. <TextView
  32. android:id="@+id/tv_qr_open_image"
  33. android:layout_width="wrap_content"
  34. android:layout_height="match_parent"
  35. android:layout_alignParentEnd="true"
  36. android:layout_alignParentRight="true"
  37. android:layout_marginEnd="15dp"
  38. android:layout_marginRight="15dp"
  39. android:clickable="true"
  40. android:focusable="true"
  41. android:gravity="center"
  42. android:textColor="#ffffff"
  43. android:textSize="20sp"/>
  44. </RelativeLayout>
  45. <!--主體部分--><SurfaceView
  46. android:id="@+id/device_qrcode_preview_view"
  47. android:layout_width="fill_parent"
  48. android:layout_height="fill_parent"
  49. android:layout_below="@+id/rl"/>
  50. <com.yzq.zxinglibrary.view.ViewfinderView
  51. android:id="@+id/vv_qr_viewfinderView"
  52. android:layout_width="wrap_content"
  53. android:layout_height="wrap_content"
  54. android:layout_gravity="center"
  55. app:device_qrcode_corner_color="#005699"
  56. app:device_qrcode_frame_color="#90FFFFFF"
  57. app:device_qrcode_laser_color="#005699"
  58. app:device_qrcode_mask_color="#60000000"
  59. app:device_qrcode_result_color="#B0000000"
  60. app:device_qrcode_result_point_color="#C0FFFF00"/>
  61. <!--app:label_text="將二維碼放入框中,即可掃描"
  62. app:label_text_color="#ffffff"
  63. app:label_text_size="16sp"-->
  64. <!--掃描燈光-->
  65. <LinearLayout
  66. android:id="@+id/bottomLayout"
  67. android:layout_width="match_parent"
  68. android:layout_height="96dp"
  69. android:layout_alignParentBottom="true"
  70. android:layout_gravity="bottom"
  71. android:background="#99000000"
  72. android:orientation="horizontal">
  73. <LinearLayout
  74. android:id="@+id/flashLightLayout"
  75. android:layout_width="0dp"
  76. android:layout_height="match_parent"
  77. android:layout_weight="1"
  78. android:gravity="center"
  79. android:orientation="vertical">
  80. <!--android:background="@drawable/device_qrcode_scan_flash_off"-->
  81. <ImageView
  82. android:id="@+id/flashLightIv"
  83. android:layout_width="36dp"
  84. android:layout_height="36dp"
  85. android:scaleType="centerCrop"
  86. android:tint="#ffffffff"/>
  87. <TextView
  88. android:id="@+id/flashLightTv"
  89. android:layout_width="match_parent"
  90. android:layout_height="wrap_content"
  91. android:layout_marginTop="5dp"
  92. android:gravity="center"
  93. android:text="打開閃光燈"
  94. android:textColor="@color/result_text"/>
  95. </LinearLayout>
  96. <LinearLayout
  97. android:id="@+id/albumLayout"
  98. android:layout_width="0dp"
  99. android:layout_height="match_parent"
  100. android:layout_weight="1"
  101. android:gravity="center"
  102. android:orientation="vertical">
  103. <ImageView
  104. android:id="@+id/img_phone"
  105. android:layout_width="36dp"
  106. android:layout_height="36dp"
  107. android:scaleType="centerCrop"
  108. android:tint="#ffffffff"
  109. android:src="@drawable/ic_photo"
  110. />
  111. <TextView
  112. android:layout_width="match_parent"
  113. android:layout_height="wrap_content"
  114. android:layout_marginTop="5dp"
  115. android:gravity="center"
  116. android:text="相冊(cè)"
  117. android:textColor="@color/result_text"/>
  118. </LinearLayout>
  119. </LinearLayout>
  120. </RelativeLayout>

清單文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas./apk/res/android"
  3. package="com.xxx.zxinglibrary">
  4. <uses-permission android:name="android.permission.CAMERA" />
  5. <uses-permission android:name="android.permission.FLASHLIGHT" />
  6. <uses-feature android:name="android.hardware.camera" />
  7. <uses-feature android:name="android.hardware.camera.autofocus" />
  8. <uses-permission android:name="android.permission.VIBRATE" />
  9. <uses-permission android:name="android.permission.WAKE_LOCK" />
  10. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  11. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  12. <application>
  13. <activity
  14. android:name=".decode.CaptureActivity"
  15. android:configChanges="orientation|screenSize"
  16. android:screenOrientation="portrait"
  17. android:theme="@android:style/Theme.NoTitleBar"
  18. android:windowSoftInputMode="adjustPan|stateHidden" />
  19. </application>
  20. </manifest>

以上的總結(jié)如果能夠幫助到你,希望給個(gè)贊,如果不能,或者有更好的推薦,不管是拍磚,還是怎樣,煩請(qǐng)留言,提供鏈接,改動(dòng)方案,或者提供更好的優(yōu)化建議,謝謝!我們定會(huì)虛心采納,謝謝!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多