[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor.xml\n/.idea/assetWizardSettings.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\n"
  },
  {
    "path": ".idea/codeStyles/Project.xml",
    "content": "<component name=\"ProjectCodeStyleConfiguration\">\n  <code_scheme name=\"Project\" version=\"173\">\n    <codeStyleSettings language=\"XML\">\n      <indentOptions>\n        <option name=\"CONTINUATION_INDENT_SIZE\" value=\"4\" />\n      </indentOptions>\n      <arrangement>\n        <rules>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>xmlns:android</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>^$</XML_NAMESPACE>\n                </AND>\n              </match>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>xmlns:.*</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>^$</XML_NAMESPACE>\n                </AND>\n              </match>\n              <order>BY_NAME</order>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>.*:id</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>\n                </AND>\n              </match>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>.*:name</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>\n                </AND>\n              </match>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>name</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>^$</XML_NAMESPACE>\n                </AND>\n              </match>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>style</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>^$</XML_NAMESPACE>\n                </AND>\n              </match>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>.*</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>^$</XML_NAMESPACE>\n                </AND>\n              </match>\n              <order>BY_NAME</order>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>.*</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>\n                </AND>\n              </match>\n              <order>ANDROID_ATTRIBUTE_ORDER</order>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>.*</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>.*</XML_NAMESPACE>\n                </AND>\n              </match>\n              <order>BY_NAME</order>\n            </rule>\n          </section>\n        </rules>\n      </arrangement>\n    </codeStyleSettings>\n  </code_scheme>\n</component>"
  },
  {
    "path": ".idea/compiler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"CompilerConfiguration\">\n    <bytecodeTargetLevel target=\"1.8\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/encodings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"Encoding\" addBOMForNewFiles=\"with NO BOM\">\n    <file url=\"PROJECT\" charset=\"UTF-8\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/gradle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GradleMigrationSettings\" migrationVersion=\"1\" />\n  <component name=\"GradleSettings\">\n    <option name=\"linkedExternalProjectsSettings\">\n      <GradleProjectSettings>\n        <option name=\"testRunner\" value=\"GRADLE\" />\n        <option name=\"distributionType\" value=\"DEFAULT_WRAPPED\" />\n        <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n        <option name=\"gradleHome\" value=\"$USER_HOME$/Develop/Android/Gradle/gradle-6.1.1\" />\n        <option name=\"gradleJvm\" value=\"1.8\" />\n        <option name=\"modules\">\n          <set>\n            <option value=\"$PROJECT_DIR$\" />\n            <option value=\"$PROJECT_DIR$/app\" />\n            <option value=\"$PROJECT_DIR$/mlkit-scanner\" />\n          </set>\n        </option>\n        <option name=\"resolveModulePerSourceSet\" value=\"false\" />\n      </GradleProjectSettings>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/inspectionProfiles/Project_Default.xml",
    "content": "<component name=\"InspectionProjectProfileManager\">\n  <profile version=\"1.0\">\n    <option name=\"myName\" value=\"Project Default\" />\n    <inspection_tool class=\"JavaDoc\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\">\n      <option name=\"TOP_LEVEL_CLASS_OPTIONS\">\n        <value>\n          <option name=\"ACCESS_JAVADOC_REQUIRED_FOR\" value=\"none\" />\n          <option name=\"REQUIRED_TAGS\" value=\"\" />\n        </value>\n      </option>\n      <option name=\"INNER_CLASS_OPTIONS\">\n        <value>\n          <option name=\"ACCESS_JAVADOC_REQUIRED_FOR\" value=\"none\" />\n          <option name=\"REQUIRED_TAGS\" value=\"\" />\n        </value>\n      </option>\n      <option name=\"METHOD_OPTIONS\">\n        <value>\n          <option name=\"ACCESS_JAVADOC_REQUIRED_FOR\" value=\"none\" />\n          <option name=\"REQUIRED_TAGS\" value=\"@return@param@throws or @exception\" />\n        </value>\n      </option>\n      <option name=\"FIELD_OPTIONS\">\n        <value>\n          <option name=\"ACCESS_JAVADOC_REQUIRED_FOR\" value=\"none\" />\n          <option name=\"REQUIRED_TAGS\" value=\"\" />\n        </value>\n      </option>\n      <option name=\"IGNORE_DEPRECATED\" value=\"false\" />\n      <option name=\"IGNORE_JAVADOC_PERIOD\" value=\"true\" />\n      <option name=\"IGNORE_DUPLICATED_THROWS\" value=\"false\" />\n      <option name=\"IGNORE_POINT_TO_ITSELF\" value=\"false\" />\n      <option name=\"myAdditionalJavadocTags\" value=\"date\" />\n    </inspection_tool>\n  </profile>\n</component>"
  },
  {
    "path": ".idea/jarRepositories.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RemoteRepositoriesConfiguration\">\n    <remote-repository>\n      <option name=\"id\" value=\"central\" />\n      <option name=\"name\" value=\"Maven Central repository\" />\n      <option name=\"url\" value=\"https://repo1.maven.org/maven2\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"jboss.community\" />\n      <option name=\"name\" value=\"JBoss Community repository\" />\n      <option name=\"url\" value=\"https://repository.jboss.org/nexus/content/repositories/public/\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"BintrayJCenter\" />\n      <option name=\"name\" value=\"BintrayJCenter\" />\n      <option name=\"url\" value=\"https://jcenter.bintray.com/\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"Google\" />\n      <option name=\"name\" value=\"Google\" />\n      <option name=\"url\" value=\"https://dl.google.com/dl/android/maven2/\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"maven\" />\n      <option name=\"name\" value=\"maven\" />\n      <option name=\"url\" value=\"https://jitpack.io\" />\n    </remote-repository>\n  </component>\n</project>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"DesignSurface\">\n    <option name=\"filePathToZoomLevelMap\">\n      <map>\n        <entry key=\"app/src/main/res/layout/activity_custom_config.xml\" value=\"0.18135528564453127\" />\n        <entry key=\"app/src/main/res/layout/activity_main.xml\" value=\"0.1\" />\n        <entry key=\"mlkit-scanner/src/main/res/layout/mn_scan_activity_scan_preview.xml\" value=\"0.1\" />\n      </map>\n    </option>\n  </component>\n  <component name=\"MarkdownProjectSettings\" wasCopied=\"true\">\n    <PreviewSettings splitEditorLayout=\"SPLIT\" splitEditorPreview=\"PREVIEW\" useGrayscaleRendering=\"false\" zoomFactor=\"1.0\" maxImageWidth=\"0\" showGitHubPageIfSynced=\"false\" allowBrowsingInPreview=\"false\" synchronizePreviewPosition=\"true\" highlightPreviewType=\"NONE\" highlightFadeOut=\"5\" highlightOnTyping=\"true\" synchronizeSourcePosition=\"true\" verticallyAlignSourceAndPreviewSyncPosition=\"true\" showSearchHighlightsInPreview=\"false\" showSelectionInPreview=\"true\" openRemoteLinks=\"true\" replaceUnicodeEmoji=\"false\" lastLayoutSetsDefault=\"false\">\n      <PanelProvider>\n        <provider providerId=\"com.vladsch.idea.multimarkdown.editor.swing.html.panel\" providerName=\"Default - Swing\" />\n      </PanelProvider>\n    </PreviewSettings>\n    <ParserSettings gitHubSyntaxChange=\"false\" emojiShortcuts=\"1\" emojiImages=\"0\">\n      <PegdownExtensions>\n        <option name=\"ABBREVIATIONS\" value=\"false\" />\n        <option name=\"ANCHORLINKS\" value=\"true\" />\n        <option name=\"ASIDE\" value=\"false\" />\n        <option name=\"ATXHEADERSPACE\" value=\"true\" />\n        <option name=\"AUTOLINKS\" value=\"true\" />\n        <option name=\"DEFINITIONS\" value=\"false\" />\n        <option name=\"DEFINITION_BREAK_DOUBLE_BLANK_LINE\" value=\"false\" />\n        <option name=\"FENCED_CODE_BLOCKS\" value=\"true\" />\n        <option name=\"FOOTNOTES\" value=\"false\" />\n        <option name=\"HARDWRAPS\" value=\"false\" />\n        <option name=\"HTML_DEEP_PARSER\" value=\"false\" />\n        <option name=\"INSERTED\" value=\"false\" />\n        <option name=\"QUOTES\" value=\"false\" />\n        <option name=\"RELAXEDHRULES\" value=\"true\" />\n        <option name=\"SMARTS\" value=\"false\" />\n        <option name=\"STRIKETHROUGH\" value=\"true\" />\n        <option name=\"SUBSCRIPT\" value=\"false\" />\n        <option name=\"SUPERSCRIPT\" value=\"false\" />\n        <option name=\"SUPPRESS_HTML_BLOCKS\" value=\"false\" />\n        <option name=\"SUPPRESS_INLINE_HTML\" value=\"false\" />\n        <option name=\"TABLES\" value=\"true\" />\n        <option name=\"TASKLISTITEMS\" value=\"true\" />\n        <option name=\"TOC\" value=\"false\" />\n        <option name=\"WIKILINKS\" value=\"false\" />\n      </PegdownExtensions>\n      <ParserOptions>\n        <option name=\"ADMONITION_EXT\" value=\"false\" />\n        <option name=\"ATTRIBUTES_EXT\" value=\"false\" />\n        <option name=\"COMMONMARK_LISTS\" value=\"true\" />\n        <option name=\"DUMMY\" value=\"false\" />\n        <option name=\"EMOJI_SHORTCUTS\" value=\"true\" />\n        <option name=\"ENUMERATED_REFERENCES_EXT\" value=\"false\" />\n        <option name=\"FLEXMARK_FRONT_MATTER\" value=\"false\" />\n        <option name=\"GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA\" value=\"false\" />\n        <option name=\"GFM_TABLE_RENDERING\" value=\"true\" />\n        <option name=\"GITBOOK_URL_ENCODING\" value=\"false\" />\n        <option name=\"GITHUB_LISTS\" value=\"false\" />\n        <option name=\"GITHUB_WIKI_LINKS\" value=\"false\" />\n        <option name=\"GITLAB_EXT\" value=\"false\" />\n        <option name=\"GITLAB_MATH_EXT\" value=\"false\" />\n        <option name=\"GITLAB_MERMAID_EXT\" value=\"false\" />\n        <option name=\"HEADER_ID_NON_ASCII_TO_LOWERCASE\" value=\"false\" />\n        <option name=\"HEADER_ID_NO_DUPED_DASHES\" value=\"false\" />\n        <option name=\"JEKYLL_FRONT_MATTER\" value=\"false\" />\n        <option name=\"MACROS_EXT\" value=\"false\" />\n        <option name=\"NO_TEXT_ATTRIBUTES\" value=\"false\" />\n        <option name=\"PARSE_HTML_ANCHOR_ID\" value=\"false\" />\n        <option name=\"PLANTUML_FENCED_CODE\" value=\"false\" />\n        <option name=\"PUML_FENCED_CODE\" value=\"false\" />\n        <option name=\"SIM_TOC_BLANK_LINE_SPACER\" value=\"true\" />\n      </ParserOptions>\n    </ParserSettings>\n    <HtmlSettings headerTopEnabled=\"false\" headerBottomEnabled=\"false\" bodyTopEnabled=\"false\" bodyBottomEnabled=\"false\" embedUrlContent=\"false\" addPageHeader=\"true\" embedImages=\"false\" embedHttpImages=\"false\" imageUriSerials=\"false\" addDocTypeHtml=\"true\" noParaTags=\"false\" plantUmlConversion=\"0\" mathConversion=\"0\">\n      <GeneratorProvider>\n        <provider providerId=\"com.vladsch.idea.multimarkdown.editor.swing.html.generator\" providerName=\"Default Swing HTML Generator\" />\n      </GeneratorProvider>\n      <headerTop />\n      <headerBottom />\n      <bodyTop />\n      <bodyBottom />\n    </HtmlSettings>\n    <CssSettings previewScheme=\"UI_SCHEME\" cssUri=\"\" isCssUriEnabled=\"false\" isCssUriSerial=\"true\" isCssTextEnabled=\"false\" isDynamicPageWidth=\"true\">\n      <StylesheetProvider>\n        <provider providerId=\"com.vladsch.idea.multimarkdown.editor.swing.html.css\" providerName=\"Default Swing Stylesheet\" />\n      </StylesheetProvider>\n      <ScriptProviders />\n      <cssText />\n      <cssUriHistory />\n    </CssSettings>\n    <HtmlExportSettings updateOnSave=\"false\" parentDir=\"\" targetDir=\"\" cssDir=\"\" scriptDir=\"\" plainHtml=\"false\" imageDir=\"\" copyLinkedImages=\"false\" imageUniquifyType=\"0\" targetPathType=\"2\" targetExt=\"\" useTargetExt=\"false\" noCssNoScripts=\"false\" useElementStyleAttribute=\"false\" linkToExportedHtml=\"true\" exportOnSettingsChange=\"true\" regenerateOnProjectOpen=\"false\" linkFormatType=\"HTTP_ABSOLUTE\" />\n    <LinkMapSettings>\n      <textMaps />\n    </LinkMapSettings>\n  </component>\n  <component name=\"ProjectRootManager\" version=\"2\" languageLevel=\"JDK_1_8\" default=\"true\" project-jdk-name=\"1.8\" project-jdk-type=\"JavaSDK\">\n    <output url=\"file://$PROJECT_DIR$/build/classes\" />\n  </component>\n  <component name=\"ProjectType\">\n    <option name=\"id\" value=\"Android\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"$PROJECT_DIR$\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "#   MNMLKitScanner 基于Google MLKit 快速集成二维码扫描,速度比zxing快\n\n##  基于Google MLKit 快速集成二维码扫描，速度比zxing快，可配置相册，闪光灯，相机可以调整焦距放大缩小，自定义扫描线颜色，自定义背景颜色，自定义遮罩层，支持同时扫多个二维码和条形码\n[![](https://jitpack.io/v/maning0303/MNMLKitScanner.svg)](https://jitpack.io/#maning0303/MNMLKitScanner)\n\n##  功能：\n    1：二维码扫描，手势缩放，无拉伸，样式自定义\n    2：相册中选取图片识别\n    3: 相机可以调整焦距放大缩小\n    4: 完全自定义遮罩层\n    5: 支持微信多个二维码/条形码同时扫描\n    6: 可调整扫描框大小\n\n\n## 截图:\n\n<div align=\"center\">\n<img src = \"screenshots/mn_mlkit_scanner_ss_01.jpg\" width=200 >\n<img src = \"screenshots/mn_mlkit_scanner_ss_02.jpg\" width=200 >\n<img src = \"screenshots/mn_mlkit_scanner_ss_03.jpg\" width=200 >\n<img src = \"screenshots/mn_mlkit_scanner_ss_05.jpg\" width=200 >\n<img src = \"screenshots/mn_mlkit_scanner_ss_04.jpg\" width=200 >\n</div>\n\n## 如何添加\n### Gradle添加：\n#### 1.在Project的build.gradle中添加仓库地址\n\n``` gradle\n\tallprojects {\n\t\trepositories {\n\t\t\t...\n\t\t\tmaven { url \"https://jitpack.io\" }\n\t\t}\n\t}\n```\n\n#### 2.在Module目录下的build.gradle中添加依赖\n``` gradle\n\tdependencies {\n\n            implementation 'com.github.maning0303:MNMLKitScanner:V1.0.4'\n            //下面版本自己控制，barcode-scanning>=17.0.2\n            implementation 'com.google.mlkit:barcode-scanning:17.0.2'\n            implementation \"androidx.camera:camera-core:1.0.2\"\n            implementation \"androidx.camera:camera-camera2:1.0.2\"\n            implementation \"androidx.camera:camera-lifecycle:1.0.2\"\n            implementation \"androidx.camera:camera-view:1.0.0-alpha25\"\n\n\t}\n```\n\n#### 3.如果想加入二维码生成功能\n``` gradle\n\tdependencies {\n            \n         implementation 'com.google.zxing:core:3.3.3'\n\n\t}\n```\ncom.maning.mlkitscanner.scan.utils.ZXingUtils 有具体的方法，详细可以查看Demo\n\n\n## 使用方法:\n###  进入需要提前申请相机权限；进入需要提前申请相机权限；进入需要提前申请相机权限；\n\n\n``` java\n        1：开始扫描：\n            //默认扫描\n            MNScanManager.startScan(this, new MNScanCallback() {\n                   @Override\n                   public void onActivityResult(int resultCode, Intent data) {\n                    switch (resultCode) {\n                        case MNScanManager.RESULT_SUCCESS:\n                            ArrayList<String> results = data.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS);\n                            break;\n                        case MNScanManager.RESULT_FAIL:\n                            String resultError = data.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR);\n                            break;\n                        case MNScanManager.RESULT_CANCLE:\n                            showToast(\"取消扫码\");\n                            break;\n                    }\n                   }\n            });\n            \n            //自定义扫描\n            MNScanConfig scanConfig = new MNScanConfig.Builder()\n                    //设置完成震动\n                    .isShowVibrate(true)\n                    //扫描完成声音\n                    .isShowBeep(true)\n                    //显示相册功能\n                    .isShowPhotoAlbum(true)\n                    //显示闪光灯\n                    .isShowLightController(true)\n                    //打开扫描页面的动画\n                    .setActivityOpenAnime(R.anim.activity_anmie_in)\n                    //退出扫描页面动画\n                    .setActivityExitAnime(R.anim.activity_anmie_out)\n                    //自定义文案\n                    .setScanHintText(\"xxxx\")\n                    .setScanHintTextColor(\"#FF0000\")\n                    .setScanHintTextSize(14)\n                    //扫描线的颜色\n                    .setScanColor(\"#FF0000\")\n                    //是否支持手势缩放\n                    .setSupportZoom(true)\n                    //扫描线样式\n                    .setLaserStyle(MNScanConfig.LaserStyle.Grid/MNScanConfig.LaserStyle.Line)\n                    //背景颜色\n                    .setBgColor(\"\")\n                    //网格扫描线的列数\n                    .setGridScanLineColumn(30)\n                    //网格高度\n                    .setGridScanLineHeight(300)\n                    //是否全屏扫描,默认全屏\n                    .setFullScreenScan(true)\n                    //单位dp\n                    .setResultPointConfigs(36, 12, 3, colorResultPointStroke, colorResultPoint)\n                    //状态栏设置\n                    .setStatusBarConfigs(colorStatusBar, true)\n                    //扫描框宽度大小比例，非全屏模式下生效，默认0.7，范围0.5-0.9\n                    .setScanFrameSizeScale(0.7f)\n                    //自定义遮罩\n                    .setCustomShadeViewLayoutID(R.layout.layout_custom_view, new MNCustomViewBindCallback() {\n                        @Override\n                        public void onBindView(View customView) {\n                            //TODO:通过findviewById 获取View\n                        }\n                    })\n                    .builder();\n            MNScanManager.startScan(this, scanConfig, new MNScanCallback() {\n                @Override\n                public void onActivityResult(int resultCode, Intent data) {\n                    switch (resultCode) {\n                        case MNScanManager.RESULT_SUCCESS:\n                            String resultSuccess = data.getStringExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS);\n                            break;\n                        case MNScanManager.RESULT_FAIL:\n                            String resultError = data.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR);\n                            break;\n                        case MNScanManager.RESULT_CANCLE:\n                            showToast(\"取消扫码\");\n                            break;\n                    }\n                }\n            });\n\n        2.提供扫描界面相关方法（自定义遮罩层会使用）：\n            /**\n             * 关闭当前页面\n             */\n            MNScanManager.closeScanPage();\n\n            /**\n             * 打开相册扫描图片\n             */\n            MNScanManager.openAlbumPage();\n\n            /**\n             * 打开手电筒\n             */\n            MNScanManager.openScanLight();\n\n            /**\n             * 关闭手电筒\n             */\n            MNScanManager.closeScanLight();\n\n            /**\n             * 手电筒是否开启\n             */\n            MNScanManager.isLightOn();\n```\n\n\n## 感谢：\n\n[googlesamples/mlkit](https://github.com/googlesamples/mlkit)\n\n[jenly1314/MLKit](https://github.com/jenly1314/MLKit)\n\n[Ye-Miao/StatusBarUtil](https://github.com/Ye-Miao/StatusBarUtil)\n\n感谢所有开源的人；\n\n\n\n## 推荐:\nName | Describe |\n--- | --- |\n[GankMM](https://github.com/maning0303/GankMM) | （Material Design & MVP & Retrofit + OKHttp & RecyclerView ...）Gank.io Android客户端：每天一张美女图片，一个视频短片，若干Android，iOS等程序干货，周一到周五每天更新，数据全部由 干货集中营 提供,持续更新。 |\n[MNUpdateAPK](https://github.com/maning0303/MNUpdateAPK) | Android APK 版本更新的下载和安装,适配7.0,简单方便。 |\n[MNImageBrowser](https://github.com/maning0303/MNImageBrowser) | 交互特效的图片浏览框架,微信向下滑动动态关闭 |\n[MNZXingCode](https://github.com/maning0303/MNZXingCode) | 快速集成二维码扫描和生成二维码 |\n[MNMLKitScanner](https://github.com/maning0303/MNMLKitScanner) | 基于Google MLKit 快速集成二维码扫描,速度比zxing快 |\n[MNPasswordEditText](https://github.com/maning0303/MNPasswordEditText) | 类似微信支付宝的密码输入框。 |\n[MClearEditText](https://github.com/maning0303/MClearEditText) | 带有删除功能的EditText |\n[MNCrashMonitor](https://github.com/maning0303/MNCrashMonitor) | Debug监听程序崩溃日志,展示崩溃日志列表，方便自己平时调试。 |\n[MNProgressHUD](https://github.com/maning0303/MNProgressHUD) | MNProgressHUD是对常用的自定义弹框封装,加载ProgressDialog,状态显示的StatusDialog和自定义Toast,支持背景颜色,圆角,边框和文字的自定义。 |\n[SwitcherView](https://github.com/maning0303/SwitcherView) | 垂直滚动的广告栏文字展示。 |\n[MNVideoPlayer](https://github.com/maning0303/MNVideoPlayer) | SurfaceView + MediaPlayer 实现的视频播放器，支持横竖屏切换，手势快进快退、调节音量，亮度等。------代码简单，新手可以看一看。 |\n[MNChangeSkin](https://github.com/maning0303/MNChangeSkin) | Android夜间模式，通过Theme实现 |\n[MNXUtilsDB](https://github.com/maning0303/MNXUtilsDB) | xUtils3 数据库模块单独抽取出来，方便使用。 |\n[MNCalendar](https://github.com/maning0303/MNCalendar) | 简单的日历控件练习，水平方向日历支持手势滑动切换，跳转月份；垂直方向日历选取区间范围。 |\n[MNSwipeToLoadDemo](https://github.com/maning0303/MNSwipeToLoadDemo) | 利用SwipeToLoadLayout实现的各种下拉刷新效果（饿了吗，京东，百度外卖，美团外卖，天猫下拉刷新等）。 |\n\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\ndef versions = rootProject.ext.versions\ndef appId = rootProject.ext.appId\ndef dependenciesGoogle = rootProject.ext.dependenciesGoogle\ndef dependenciesOther = rootProject.ext.dependenciesOther\n\nandroid {\n    compileSdkVersion versions.compileSdkVersion\n    ndkVersion \"20.1.5948944\"\n    defaultConfig {\n        applicationId appId.app\n        minSdkVersion versions.minSdkVersion\n        targetSdkVersion versions.targetSdkVersion\n        versionCode versions.versionCode\n        versionName versions.versionName\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: \"libs\", include: [\"*.jar\"])\n    implementation 'androidx.appcompat:appcompat:1.1.0'\n    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'\n    // 循环引入库\n    dependenciesGoogle.each { k, v -> api v }\n    dependenciesOther.each { k, v -> api v }\n    dependenciesDebug.each { k, v -> debugImplementation v }\n\n    //扫码核心库\n    implementation project(path: ':mlkit-scanner')\n//    implementation 'com.github.maning0303:MNMLKitScanner:V1.0.4'\n\n    implementation 'com.google.mlkit:barcode-scanning:17.0.2'\n    implementation 'androidx.camera:camera-core:1.0.2'\n    implementation 'androidx.camera:camera-camera2:1.0.2'\n    implementation 'androidx.camera:camera-lifecycle:1.0.2'\n    implementation 'androidx.camera:camera-view:1.0.0-alpha25'\n\n    implementation 'com.google.zxing:core:3.3.3'\n\n\n}"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "app/src/androidTest/java/com/maning/mlkitscanner/ExampleInstrumentedTest.java",
    "content": "package com.maning.mlkitscanner;\n\nimport android.content.Context;\n\nimport androidx.test.platform.app.InstrumentationRegistry;\nimport androidx.test.ext.junit.runners.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();\n        assertEquals(\"com.maning.mlkitscanner\", appContext.getPackageName());\n    }\n}"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.maning.mlkitscanner.demo\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n\n        <activity\n            android:name=\".CustomConfigActivity\"\n            android:screenOrientation=\"portrait\" />\n\n        <activity android:name=\".MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/com/maning/mlkitscanner/demo/CustomConfigActivity.java",
    "content": "package com.maning.mlkitscanner.demo;\n\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.CheckBox;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.RadioButton;\nimport android.widget.SeekBar;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.maning.mlkitscanner.scan.MNScanManager;\nimport com.maning.mlkitscanner.scan.callback.MNCustomViewBindCallback;\nimport com.maning.mlkitscanner.scan.callback.act.MNScanCallback;\nimport com.maning.mlkitscanner.scan.model.MNScanConfig;\n\nimport java.util.ArrayList;\n\nimport top.defaults.colorpicker.ColorPickerPopup;\n\npublic class CustomConfigActivity extends AppCompatActivity implements View.OnClickListener {\n\n    /**\n     * 是否显示相册功能\n     */\n    private CheckBox mCbPhoto;\n    /**\n     * 是否显示闪光灯\n     */\n    private CheckBox mCbLight;\n    /**\n     * 是否需要全屏扫描识别（默认）\n     */\n    private CheckBox mCbFullscreenScan;\n    /**\n     * 是否开启扫描完成震动提醒\n     */\n    private CheckBox mCbVibrate;\n    /**\n     * 是否开启扫描完成声音提醒\n     */\n    private CheckBox mCbBeep;\n    /**\n     * 是否完全自定义遮罩层\n     */\n    private CheckBox mCbCustomView;\n    /**\n     * 输入自定义提示文案\n     */\n    private EditText mEtHintText;\n    /**\n     * 文字大小(sp)\n     */\n    private EditText mEtHintTextSize;\n    /**\n     * 网格扫描高度\n     */\n    private EditText mEtGridlineHeight;\n    /**\n     * 网格扫描列数\n     */\n    private EditText mEtGridlineNum;\n\n    private TextView mBtnColorPickerText;\n    private TextView mBtnColorPickerLine;\n    private TextView mBtnColorPickerBg;\n    /**\n     * 线性\n     */\n    private RadioButton mRbScanlineLine;\n    /**\n     * 网格\n     */\n    private RadioButton mRbScanlineGrid;\n\n\n    private String colorText = \"#22CE6B\";\n    private String colorLine = \"#22CE6B\";\n    private String colorBackground = \"#22FF0000\";\n    private String colorStatusBar = \"#00000000\";\n    private String colorResultPoint = \"#CC22CE6B\";\n    private String colorResultPointStroke = \"#FFFFFFFF\";\n\n    /**\n     * 是否支持手势缩放\n     */\n    private CheckBox mCbSupportZoom;\n    /**\n     * 是否状态栏黑色字体\n     */\n    private CheckBox mCbStatusDark;\n    private TextView mBtnColorStatusbarBg;\n    private SeekBar mSbarFrameSize;\n    private TextView mTvFrameSize;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_custom_config);\n        initView();\n    }\n\n    private void initView() {\n        mCbPhoto = (CheckBox) findViewById(R.id.cb_photo);\n        mCbLight = (CheckBox) findViewById(R.id.cb_light);\n        mCbFullscreenScan = (CheckBox) findViewById(R.id.cb_fullscreen_scan);\n        mCbVibrate = (CheckBox) findViewById(R.id.cb_vibrate);\n        mCbBeep = (CheckBox) findViewById(R.id.cb_beep);\n        mCbCustomView = (CheckBox) findViewById(R.id.cb_custom_view);\n        mEtHintText = (EditText) findViewById(R.id.et_hint_text);\n        mEtHintTextSize = (EditText) findViewById(R.id.et_hint_text_size);\n        mEtGridlineHeight = (EditText) findViewById(R.id.et_gridline_height);\n        mEtGridlineNum = (EditText) findViewById(R.id.et_gridline_num);\n        mBtnColorPickerText = (TextView) findViewById(R.id.btn_color_picker_text);\n        mBtnColorPickerText.setOnClickListener(this);\n        mBtnColorPickerLine = (TextView) findViewById(R.id.btn_color_picker_line);\n        mBtnColorPickerLine.setOnClickListener(this);\n        mBtnColorPickerBg = (TextView) findViewById(R.id.btn_color_picker_bg);\n        mBtnColorPickerBg.setOnClickListener(this);\n        mRbScanlineLine = (RadioButton) findViewById(R.id.rb_scanline_line);\n        mRbScanlineGrid = (RadioButton) findViewById(R.id.rb_scanline_grid);\n        mCbSupportZoom = (CheckBox) findViewById(R.id.cb_support_zoom);\n        mCbStatusDark = (CheckBox) findViewById(R.id.cb_status_dark);\n        mBtnColorStatusbarBg = (TextView) findViewById(R.id.btn_color_statusbar_bg);\n        mBtnColorStatusbarBg.setOnClickListener(this);\n        mTvFrameSize = (TextView) findViewById(R.id.tv_frameSize);\n        mSbarFrameSize = (SeekBar) findViewById(R.id.sbar_frameSize);\n        mSbarFrameSize.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {\n            @Override\n            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {\n                if (mSbarFrameSize.getProgress() < 50) {\n                    mSbarFrameSize.setProgress(50);\n                }\n                if (mSbarFrameSize.getProgress() > 90) {\n                    mSbarFrameSize.setProgress(90);\n                }\n                mTvFrameSize.setText(\"扫描框大小比例：\" + (mSbarFrameSize.getProgress() / 100f) + \"\\n（非全屏模式生效，范围0.5-0.9）\");\n            }\n\n            @Override\n            public void onStartTrackingTouch(SeekBar seekBar) {\n\n            }\n\n            @Override\n            public void onStopTrackingTouch(SeekBar seekBar) {\n\n            }\n        });\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_color_picker_text:\n                new ColorPickerPopup.Builder(this)\n                        .initialColor(Color.parseColor(colorText))\n                        .enableBrightness(true)\n                        .enableAlpha(false)\n                        .okTitle(\"选择颜色\")\n                        .cancelTitle(\"取消\")\n                        .showIndicator(true)\n                        .showValue(true)\n                        .build()\n                        .show(mBtnColorPickerText, new ColorPickerPopup.ColorPickerObserver() {\n                            @Override\n                            public void onColorPicked(int color) {\n                                colorText = getHexString(color);\n                                mBtnColorPickerText.setBackgroundColor(color);\n                            }\n                        });\n                break;\n            case R.id.btn_color_picker_line:\n                new ColorPickerPopup.Builder(this)\n                        .initialColor(Color.parseColor(colorLine))\n                        .enableBrightness(true)\n                        .enableAlpha(false)\n                        .okTitle(\"选择颜色\")\n                        .cancelTitle(\"取消\")\n                        .showIndicator(true)\n                        .showValue(true)\n                        .build()\n                        .show(mBtnColorPickerLine, new ColorPickerPopup.ColorPickerObserver() {\n                            @Override\n                            public void onColorPicked(int color) {\n                                colorLine = getHexString(color);\n                                mBtnColorPickerLine.setBackgroundColor(color);\n                            }\n                        });\n                break;\n            case R.id.btn_color_picker_bg:\n                new ColorPickerPopup.Builder(this)\n                        .initialColor(Color.parseColor(colorBackground))\n                        .enableBrightness(true)\n                        .enableAlpha(true)\n                        .okTitle(\"选择颜色\")\n                        .cancelTitle(\"取消\")\n                        .showIndicator(true)\n                        .showValue(true)\n                        .build()\n                        .show(mBtnColorPickerBg, new ColorPickerPopup.ColorPickerObserver() {\n                            @Override\n                            public void onColorPicked(int color) {\n                                colorBackground = getHexString(color);\n                                mBtnColorPickerBg.setBackgroundColor(color);\n                            }\n                        });\n                break;\n            case R.id.btn_color_statusbar_bg:\n                new ColorPickerPopup.Builder(this)\n                        .initialColor(Color.parseColor(colorStatusBar))\n                        .enableBrightness(true)\n                        .enableAlpha(true)\n                        .okTitle(\"选择颜色\")\n                        .cancelTitle(\"取消\")\n                        .showIndicator(true)\n                        .showValue(true)\n                        .build()\n                        .show(mBtnColorStatusbarBg, new ColorPickerPopup.ColorPickerObserver() {\n                            @Override\n                            public void onColorPicked(int color) {\n                                colorStatusBar = getHexString(color);\n                                mBtnColorStatusbarBg.setBackgroundColor(color);\n                            }\n                        });\n                break;\n            default:\n                break;\n        }\n    }\n\n    private String getHexString(int color) {\n        String format = String.format(\"#%X\", color);\n        Log.e(\"=====\", \"format:\" + format);\n        if (\"#0\".equals(format)) {\n            format = \"#00000000\";\n            Log.e(\"=====\", \"format:\" + format);\n        }\n        return format;\n    }\n\n    public void scanCode(View view) {\n        //需要判断有没有权限\n        MNScanConfig scanConfig = new MNScanConfig.Builder()\n                //设置完成震动\n                .isShowVibrate(mCbVibrate.isChecked())\n                //扫描完成声音\n                .isShowBeep(mCbBeep.isChecked())\n                //显示相册功能\n                .isShowPhotoAlbum(mCbPhoto.isChecked())\n                //显示闪光灯\n                .isShowLightController(mCbLight.isChecked())\n                //打开扫描页面的动画\n                .setActivityOpenAnime(R.anim.activity_anmie_in)\n                //退出扫描页面动画\n                .setActivityExitAnime(R.anim.activity_anmie_out)\n                //自定义文案\n                .setScanHintText(mEtHintText.getText().toString())\n                .setScanHintTextColor(colorText)\n                .setScanHintTextSize(TextUtils.isEmpty(mEtHintTextSize.getText().toString()) ? 14 : Integer.parseInt(mEtHintTextSize.getText().toString()))\n                //扫描线的颜色\n                .setScanColor(colorLine)\n                //是否支持手势缩放\n                .setSupportZoom(mCbSupportZoom.isChecked())\n                //扫描线样式\n                .setLaserStyle(mRbScanlineGrid.isChecked() ? MNScanConfig.LaserStyle.Grid : MNScanConfig.LaserStyle.Line)\n                //背景颜色\n                .setBgColor(colorBackground)\n                //网格扫描线的列数\n                .setGridScanLineColumn(TextUtils.isEmpty(mEtGridlineNum.getText().toString()) ? 30 : Integer.parseInt(mEtGridlineNum.getText().toString()))\n                //网格高度\n                .setGridScanLineHeight(TextUtils.isEmpty(mEtGridlineHeight.getText().toString()) ? 0 : Integer.parseInt(mEtGridlineHeight.getText().toString()))\n                //是否全屏扫描,默认全屏\n                .setFullScreenScan(mCbFullscreenScan.isChecked())\n                //单位dp\n                .setResultPointConfigs(36, 12, 3, colorResultPointStroke, colorResultPoint)\n                //状态栏设置\n                .setStatusBarConfigs(colorStatusBar, mCbStatusDark.isChecked())\n                //扫描框宽度大小比例，非全屏模式下生效，默认0.7，范围0.5-0.9\n                .setScanFrameSizeScale(mSbarFrameSize.getProgress() / 100f)\n                //自定义遮罩\n                .setCustomShadeViewLayoutID(mCbCustomView.isChecked() ? R.layout.layout_custom_view : 0, new MNCustomViewBindCallback() {\n                    @Override\n                    public void onBindView(View customView) {\n                        if (customView == null) {\n                            return;\n                        }\n                        ImageView iv_back = customView.findViewById(R.id.iv_back);\n                        ImageView iv_photo = customView.findViewById(R.id.iv_photo);\n                        LinearLayout btn_scan_light = customView.findViewById(R.id.btn_scan_light);\n                        final ImageView iv_scan_light = customView.findViewById(R.id.iv_scan_light);\n                        final TextView tv_scan_light = customView.findViewById(R.id.tv_scan_light);\n                        LinearLayout btn_my_card = customView.findViewById(R.id.btn_my_card);\n                        LinearLayout btn_scan_record = customView.findViewById(R.id.btn_scan_record);\n                        iv_back.setOnClickListener(new View.OnClickListener() {\n                            @Override\n                            public void onClick(View v) {\n                                //关闭扫描页面\n                                MNScanManager.closeScanPage();\n                            }\n                        });\n                        btn_scan_light.setOnClickListener(new View.OnClickListener() {\n                            @Override\n                            public void onClick(View v) {\n                                //手电筒\n                                if (MNScanManager.isLightOn()) {\n                                    MNScanManager.closeScanLight();\n                                    iv_scan_light.setImageResource(R.drawable.icon_custom_light_close);\n                                    tv_scan_light.setText(\"开启手电筒\");\n                                } else {\n                                    MNScanManager.openScanLight();\n                                    iv_scan_light.setImageResource(R.drawable.icon_custom_light_open);\n                                    tv_scan_light.setText(\"关闭手电筒\");\n                                }\n                            }\n                        });\n                        iv_photo.setOnClickListener(new View.OnClickListener() {\n                            @Override\n                            public void onClick(View v) {\n                                //打开相册扫描\n                                MNScanManager.openAlbumPage();\n                            }\n                        });\n                        btn_my_card.setOnClickListener(new View.OnClickListener() {\n                            @Override\n                            public void onClick(View v) {\n                                //我的名片\n                                showToast(\"我的名片\");\n                            }\n                        });\n                        btn_scan_record.setOnClickListener(new View.OnClickListener() {\n                            @Override\n                            public void onClick(View v) {\n                                //扫码记录\n                                showToast(\"扫码记录\");\n                            }\n                        });\n                    }\n                })\n                .builder();\n        MNScanManager.startScan(this, scanConfig, new MNScanCallback() {\n            @Override\n            public void onActivityResult(int resultCode, Intent data) {\n                handlerResult(resultCode, data);\n            }\n        });\n    }\n\n    private void showToast(String msg) {\n        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();\n    }\n\n\n    private void handlerResult(int resultCode, Intent data) {\n        switch (resultCode) {\n            case MNScanManager.RESULT_SUCCESS:\n                ArrayList<String> results = data.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS);\n                StringBuilder resultStr = new StringBuilder();\n                for (int i = 0; i < results.size(); i++) {\n                    resultStr.append(\"第\" + (i + 1) + \"条：\");\n                    resultStr.append(results.get(i));\n                    resultStr.append(\"\\n\");\n                }\n                showToast(resultStr.toString());\n                break;\n            case MNScanManager.RESULT_FAIL:\n                String resultError = data.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR);\n                showToast(resultError);\n                break;\n            case MNScanManager.RESULT_CANCLE:\n                showToast(\"取消扫码\");\n                break;\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/maning/mlkitscanner/demo/MainActivity.java",
    "content": "package com.maning.mlkitscanner.demo;\n\nimport android.Manifest;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.Button;\nimport android.widget.CheckBox;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.Spinner;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.maning.mlkitscanner.scan.MNScanManager;\nimport com.maning.mlkitscanner.scan.callback.act.MNScanCallback;\nimport com.maning.mlkitscanner.scan.utils.ZXingUtils;\n\nimport java.util.ArrayList;\n\npublic class MainActivity extends AppCompatActivity implements View.OnClickListener {\n\n    private Button btnScanDefault;\n    private Button btnScanCustom;\n    private TextView tvResults;\n\n    private ImageView imageView;\n    private EditText editText;\n    private CheckBox checkbox;\n    private CheckBox checkbox2;\n    private Spinner mSpColorBlack;\n    private Spinner mSpColorWhite;\n    private Spinner mSpMargin;\n\n    private String error_correction_level;\n    private int margin = 0;\n    private int color_black = Color.BLACK;\n    private int color_white = Color.WHITE;\n    private Spinner mSpErrorCorrectionLevel;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        initView();\n        requestCameraPerm();\n    }\n\n    private void initView() {\n        btnScanDefault = (Button) findViewById(R.id.btn_scan_default);\n        btnScanCustom = (Button) findViewById(R.id.btn_scan_custom);\n        btnScanDefault.setOnClickListener(this);\n        btnScanCustom.setOnClickListener(this);\n        tvResults = (TextView) findViewById(R.id.tv_results);\n\n        imageView = (ImageView) findViewById(R.id.imageView);\n        editText = (EditText) findViewById(R.id.editText);\n        checkbox = (CheckBox) findViewById(R.id.checkbox);\n        checkbox2 = (CheckBox) findViewById(R.id.checkbox2);\n        mSpColorBlack = (Spinner) findViewById(R.id.sp_color_black);\n        mSpColorWhite = (Spinner) findViewById(R.id.sp_color_white);\n        mSpMargin = (Spinner) findViewById(R.id.sp_margin);\n        mSpMargin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {\n            @Override\n            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n                margin = Integer.parseInt(getResources().getStringArray(R.array.spinarr_margin)[position]);\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parent) {\n\n            }\n        });\n        mSpColorBlack.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {\n            @Override\n            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n                String str_color_black = getResources().getStringArray(R.array.spinarr_color_black)[position];\n                if (str_color_black.equals(\"黑色\")) {\n                    color_black = Color.BLACK;\n                } else if (str_color_black.equals(\"白色\")) {\n                    color_black = Color.WHITE;\n                } else if (str_color_black.equals(\"蓝色\")) {\n                    color_black = Color.BLUE;\n                } else if (str_color_black.equals(\"绿色\")) {\n                    color_black = Color.GREEN;\n                } else if (str_color_black.equals(\"黄色\")) {\n                    color_black = Color.YELLOW;\n                } else if (str_color_black.equals(\"红色\")) {\n                    color_black = Color.RED;\n                } else {\n                    color_black = Color.BLACK;\n                }\n\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parent) {\n\n            }\n        });\n        mSpColorWhite.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {\n            @Override\n            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n                String str_color_white = getResources().getStringArray(R.array.spinarr_color_white)[position];\n                if (str_color_white.equals(\"黑色\")) {\n                    color_white = Color.BLACK;\n                } else if (str_color_white.equals(\"白色\")) {\n                    color_white = Color.WHITE;\n                } else if (str_color_white.equals(\"蓝色\")) {\n                    color_white = Color.BLUE;\n                } else if (str_color_white.equals(\"绿色\")) {\n                    color_white = Color.GREEN;\n                } else if (str_color_white.equals(\"黄色\")) {\n                    color_white = Color.YELLOW;\n                } else if (str_color_white.equals(\"红色\")) {\n                    color_white = Color.RED;\n                } else {\n                    color_white = Color.WHITE;\n                }\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parent) {\n\n            }\n        });\n        mSpErrorCorrectionLevel = (Spinner) findViewById(R.id.sp_error_correction_level);\n        mSpErrorCorrectionLevel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {\n            @Override\n            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n                error_correction_level = getResources().getStringArray(R.array.spinarr_error_correction)[position];\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parent) {\n\n            }\n        });\n    }\n\n    public void requestCameraPerm() {\n        //判断权限\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {\n                requestPermissions(new String[]{Manifest.permission.CAMERA}, 10010);\n            }\n        }\n    }\n\n    @Override\n    public void onClick(View view) {\n        if (view.getId() == R.id.btn_scan_default) {\n            MNScanManager.startScan(this, new MNScanCallback() {\n                @Override\n                public void onActivityResult(int resultCode, Intent data) {\n                    handlerResult(resultCode, data);\n                }\n            });\n        }else if (view.getId() == R.id.btn_scan_custom) {\n            //跳转到自定义界面\n            startActivity(new Intent(this, CustomConfigActivity.class));\n        }\n    }\n\n    private void handlerResult(int resultCode, Intent data) {\n        if (data == null) {\n            return;\n        }\n        switch (resultCode) {\n            default:\n                break;\n            case MNScanManager.RESULT_SUCCESS:\n                ArrayList<String> results = data.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS);\n                StringBuilder resultStr = new StringBuilder();\n                for (int i = 0; i < results.size(); i++) {\n                    resultStr.append(\"第\" + (i + 1) + \"条：\");\n                    resultStr.append(results.get(i));\n                    resultStr.append(\"\\n\");\n                }\n                tvResults.setText(resultStr.toString());\n                break;\n            case MNScanManager.RESULT_FAIL:\n                String resultError = data.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR);\n                showToast(resultError);\n                break;\n            case MNScanManager.RESULT_CANCLE:\n                showToast(\"取消扫码\");\n                break;\n        }\n    }\n\n    private void showToast(String msg) {\n        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();\n    }\n\n\n    public void createQRImage(View view) {\n        String str = editText.getText().toString();\n\n        if (TextUtils.isEmpty(str)) {\n            Toast.makeText(this, \"字符串不能为空\", Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        Bitmap qrImage;\n        Bitmap logo = null;\n        Bitmap foreground_bitmap = null;\n        if (checkbox.isChecked()) {\n            logo = BitmapFactory.decodeResource(getResources(), R.drawable.ic_wx);\n        }\n        if (checkbox2.isChecked()) {\n            foreground_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tmp);\n        }\n        qrImage = ZXingUtils.createQRCodeImage(str, 500, margin, color_black, color_white, error_correction_level, logo, foreground_bitmap);\n        if (qrImage != null) {\n            imageView.setImageBitmap(qrImage);\n        } else {\n            Toast.makeText(this, \"生成失败\", Toast.LENGTH_SHORT).show();\n        }\n\n    }\n}"
  },
  {
    "path": "app/src/main/res/anim/activity_anmie_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:interpolator=\"@android:anim/decelerate_interpolator\">\n    <scale\n        android:duration=\"200\"\n        android:fromXScale=\"0.1\"\n        android:fromYScale=\"0.1\"\n        android:pivotX=\"50%p\"\n        android:pivotY=\"50%p\"\n        android:toXScale=\"1.0\"\n        android:toYScale=\"1.0\" />\n    <alpha\n        android:duration=\"200\"\n        android:fromAlpha=\"0.1\"\n        android:toAlpha=\"1.0\" />\n</set>"
  },
  {
    "path": "app/src/main/res/anim/activity_anmie_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:interpolator=\"@android:anim/decelerate_interpolator\">\n    <scale\n        android:duration=\"200\"\n        android:fromXScale=\"1.0\"\n        android:fromYScale=\"1.0\"\n        android:pivotX=\"50%p\"\n        android:pivotY=\"50%p\"\n        android:toXScale=\"0.1\"\n        android:toYScale=\"0.1\" />\n    <alpha\n        android:duration=\"200\"\n        android:fromAlpha=\"1.0\"\n        android:toAlpha=\"0.1\" />\n</set>"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#3DDC84\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path android:pathData=\"M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"85.84757\"\n                android:endY=\"92.4963\"\n                android:startX=\"42.9492\"\n                android:startY=\"49.59793\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\" />\n</vector>"
  },
  {
    "path": "app/src/main/res/layout/activity_custom_config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:focusable=\"true\"\n        android:focusableInTouchMode=\"true\"\n        android:orientation=\"vertical\"\n        android:padding=\"10dp\">\n\n        <Button\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@color/colorPrimary\"\n            android:onClick=\"scanCode\"\n            android:text=\"自定义扫描\"\n            android:textColor=\"#FFFFFF\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"10dp\"\n                android:layout_marginBottom=\"10dp\"\n                android:background=\"@color/colorAccent\" />\n\n            <CheckBox\n                android:id=\"@+id/cb_photo\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:checked=\"true\"\n                android:text=\"是否显示相册功能\" />\n\n            <CheckBox\n                android:id=\"@+id/cb_light\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:checked=\"true\"\n                android:text=\"是否显示闪光灯\" />\n\n            <CheckBox\n                android:id=\"@+id/cb_support_zoom\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:checked=\"true\"\n                android:text=\"是否支持手势缩放\" />\n\n            <CheckBox\n                android:id=\"@+id/cb_fullscreen_scan\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:checked=\"false\"\n                android:text=\"是否需要全屏扫描识别（默认）\" />\n\n            <CheckBox\n                android:id=\"@+id/cb_vibrate\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:checked=\"true\"\n                android:text=\"是否开启扫描完成震动提醒\" />\n\n            <CheckBox\n                android:id=\"@+id/cb_beep\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:checked=\"true\"\n                android:text=\"是否开启扫描完成声音提醒\" />\n\n            <CheckBox\n                android:id=\"@+id/cb_custom_view\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:checked=\"true\"\n                android:text=\"是否完全自定义遮罩层\" />\n\n            <CheckBox\n                android:id=\"@+id/cb_status_dark\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:checked=\"false\"\n                android:text=\"是否状态栏黑色字体\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\">\n\n                <EditText\n                    android:id=\"@+id/et_hint_text\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"44dp\"\n                    android:layout_weight=\"4\"\n                    android:hint=\"输入自定义提示文案\"\n                    android:textSize=\"14sp\" />\n\n                <EditText\n                    android:id=\"@+id/et_hint_text_size\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"44dp\"\n                    android:layout_marginLeft=\"10dp\"\n                    android:layout_weight=\"2\"\n                    android:hint=\"文字大小(sp)\"\n                    android:inputType=\"number\"\n                    android:textSize=\"14sp\" />\n\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"50dp\"\n                android:orientation=\"horizontal\">\n\n                <EditText\n                    android:id=\"@+id/et_gridline_height\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"44dp\"\n                    android:layout_weight=\"2\"\n                    android:hint=\"网格扫描高度\"\n                    android:inputType=\"number\"\n                    android:textSize=\"14sp\" />\n\n                <EditText\n                    android:id=\"@+id/et_gridline_num\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"44dp\"\n                    android:layout_marginLeft=\"10dp\"\n                    android:layout_weight=\"2\"\n                    android:hint=\"网格扫描列数\"\n                    android:inputType=\"number\"\n                    android:textSize=\"14sp\" />\n\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"10dp\"\n                android:gravity=\"center_vertical\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"提示文字的颜色：\"\n                    android:textSize=\"14sp\" />\n\n\n                <TextView\n                    android:id=\"@+id/btn_color_picker_text\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"#22CE6B\" />\n\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"10dp\"\n                android:gravity=\"center_vertical\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"扫描线的颜色：\"\n                    android:textSize=\"14sp\" />\n\n\n                <TextView\n                    android:id=\"@+id/btn_color_picker_line\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"#22CE6B\" />\n\n            </LinearLayout>\n\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"10dp\"\n                android:gravity=\"center_vertical\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"遮罩背景颜色(非全屏模式下生效)：\"\n                    android:textSize=\"14sp\" />\n\n\n                <TextView\n                    android:id=\"@+id/btn_color_picker_bg\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"#33FF0000\" />\n\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"10dp\"\n                android:gravity=\"center_vertical\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"状态栏颜色：\"\n                    android:textSize=\"14sp\" />\n\n\n                <TextView\n                    android:id=\"@+id/btn_color_statusbar_bg\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"#00000000\" />\n\n            </LinearLayout>\n\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"10dp\"\n                android:gravity=\"center_vertical\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"扫描线样式：\"\n                    android:textSize=\"14sp\" />\n\n                <RadioGroup\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <RadioButton\n                        android:id=\"@+id/rb_scanline_line\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginRight=\"20dp\"\n                        android:text=\"线性\" />\n\n                    <RadioButton\n                        android:id=\"@+id/rb_scanline_grid\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:checked=\"true\"\n                        android:text=\"网格\" />\n\n                </RadioGroup>\n\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"10dp\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"vertical\">\n\n                <TextView\n                    android:id=\"@+id/tv_frameSize\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"扫描框大小比例:0.7\\n（非全屏模式生效，范围0.5-0.9）\"\n                    android:textSize=\"14sp\" />\n\n                <SeekBar\n                    android:id=\"@+id/sbar_frameSize\"\n                    style=\"?android:attr/progressBarStyleHorizontal\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"10dp\"\n                    android:layout_marginBottom=\"10dp\"\n                    android:max=\"100\"\n                    android:progress=\"70\" />\n\n            </LinearLayout>\n\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"10dp\"\n                android:layout_marginTop=\"10dp\"\n                android:background=\"@color/colorAccent\" />\n\n        </LinearLayout>\n\n    </LinearLayout>\n\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".MainActivity\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:padding=\"10dp\">\n\n        <Button\n            android:id=\"@+id/btn_scan_default\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"10dp\"\n            android:background=\"@color/colorPrimary\"\n            android:text=\"默认扫描\"\n            android:textColor=\"#FFFFFF\" />\n\n        <Button\n            android:id=\"@+id/btn_scan_custom\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@color/colorPrimary\"\n            android:text=\"自定义扫描\"\n            android:textColor=\"#FFFFFF\" />\n\n        <TextView\n            android:id=\"@+id/tv_results\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"10dp\"\n            android:text=\"扫描结果显示...\"\n            />\n\n        <Button\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"10dp\"\n            android:background=\"@color/colorPrimary\"\n            android:onClick=\"createQRImage\"\n            android:text=\"生成二维码\"\n            android:textColor=\"#FFFFFF\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"10dp\"\n            android:orientation=\"horizontal\">\n\n            <EditText\n                android:id=\"@+id/editText\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"50dp\"\n                android:hint=\"输入要生成二维码的文本\"\n                android:textSize=\"15sp\" />\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"10dp\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"horizontal\">\n\n            <CheckBox\n                android:id=\"@+id/checkbox\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:text=\"中间Logo\" />\n\n            <CheckBox\n                android:id=\"@+id/checkbox2\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:text=\"图片替代二维码(不建议，太花识别率可能比较低)\" />\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"40dp\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:gravity=\"center_vertical\"\n                android:text=\"前景色：\" />\n\n            <Spinner\n                android:id=\"@+id/sp_color_black\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:entries=\"@array/spinarr_color_black\" />\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:gravity=\"center_vertical\"\n                android:text=\"背景色：\" />\n\n            <Spinner\n                android:id=\"@+id/sp_color_white\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:entries=\"@array/spinarr_color_white\" />\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"40dp\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:gravity=\"center_vertical\"\n                android:text=\"边距：\" />\n\n            <Spinner\n                android:id=\"@+id/sp_margin\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:entries=\"@array/spinarr_margin\" />\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_marginLeft=\"10dp\"\n                android:gravity=\"center_vertical\"\n                android:text=\"容错率：\" />\n\n            <Spinner\n                android:id=\"@+id/sp_error_correction_level\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:entries=\"@array/spinarr_error_correction\" />\n\n        </LinearLayout>\n\n        <ImageView\n            android:id=\"@+id/imageView\"\n            android:layout_width=\"200dp\"\n            android:layout_height=\"200dp\"\n            android:layout_gravity=\"center_horizontal\"\n            android:scaleType=\"fitXY\"\n            android:src=\"@mipmap/ic_launcher\" />\n\n    </LinearLayout>\n\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/layout_custom_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:background=\"#000000\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\">\n\n        <ImageView\n            android:id=\"@+id/iv_back\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"50dp\"\n            android:padding=\"15dp\"\n            android:src=\"@drawable/icon_custom_back\" />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerInParent=\"true\"\n            android:text=\"扫一扫\"\n            android:textColor=\"#FFFFFF\"\n            android:textSize=\"18sp\"\n            android:textStyle=\"bold\" />\n\n        <ImageView\n            android:id=\"@+id/iv_photo\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"50dp\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_marginRight=\"10dp\"\n            android:padding=\"12dp\"\n            android:src=\"@drawable/icon_custom_photo\" />\n\n    </RelativeLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:gravity=\"center\"\n        android:paddingTop=\"12dp\"\n        android:paddingBottom=\"16dp\">\n\n        <LinearLayout\n            android:id=\"@+id/btn_scan_light\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\">\n\n            <ImageView\n                android:id=\"@+id/iv_scan_light\"\n                android:layout_width=\"50dp\"\n                android:layout_height=\"50dp\"\n                android:padding=\"12dp\"\n                android:src=\"@drawable/icon_custom_light_close\" />\n\n            <TextView\n                android:id=\"@+id/tv_scan_light\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"打开手电筒\"\n                android:textColor=\"#FFFFFF\"\n                android:textSize=\"12sp\" />\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/btn_my_card\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\">\n\n            <ImageView\n                android:layout_width=\"50dp\"\n                android:layout_height=\"50dp\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/icon_custom_my_card\" />\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"我的名片\"\n                android:textColor=\"#FFFFFF\"\n                android:textSize=\"12sp\" />\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/btn_scan_record\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\">\n\n            <ImageView\n                android:layout_width=\"50dp\"\n                android:layout_height=\"50dp\"\n                android:padding=\"12dp\"\n                android:src=\"@drawable/icon_custom_record\" />\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"扫码记录\"\n                android:textColor=\"#FFFFFF\"\n                android:textSize=\"12sp\" />\n\n        </LinearLayout>\n\n    </LinearLayout>\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/values/array.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string-array name=\"spinarr_error_correction\">\n        <item>L </item>\n        <item>M </item>\n        <item>Q</item>\n        <item>H</item>\n    </string-array>\n\n    <string-array name=\"spinarr_margin\">\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n        <item>3</item>\n        <item>4</item>\n    </string-array>\n\n    <string-array name=\"spinarr_color_black\">\n        <item>黑色</item>\n        <item>白色</item>\n        <item>蓝色</item>\n        <item>绿色</item>\n        <item>黄色</item>\n        <item>红色</item>\n    </string-array>\n\n    <string-array name=\"spinarr_color_white\">\n        <item>白色</item>\n        <item>黑色</item>\n        <item>蓝色</item>\n        <item>绿色</item>\n        <item>黄色</item>\n        <item>红色</item>\n    </string-array>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#6200EE</color>\n    <color name=\"colorPrimaryDark\">#3700B3</color>\n    <color name=\"colorAccent\">#03DAC5</color>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">MLKit扫码</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>"
  },
  {
    "path": "app/src/test/java/com/maning/mlkitscanner/ExampleUnitTest.java",
    "content": "package com.maning.mlkitscanner;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\napply from: \"config.gradle\"\n\nbuildscript {\n    repositories {\n        google()\n        jcenter()\n        maven { url 'https://jitpack.io' }\n    }\n    dependencies {\n        classpath \"com.android.tools.build:gradle:4.0.0\"\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n        maven { url 'https://jitpack.io' }\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}"
  },
  {
    "path": "config.gradle",
    "content": "/**\n * 全局统一配置\n */\next {\n\n    /**\n     * 版本统一管理\n     */\n    versions = [\n            versionCode      : 101,                    //版本号\n            versionName      : \"1.0.1\",              //版本名称\n\n            compileSdkVersion: 29,\n            minSdkVersion    : 21,\n            targetSdkVersion : 28,\n\n    ]\n\n    appId = [\n            \"app\": \"com.maning.mlkitscanner.demo\",\n    ]\n\n    dependenciesGoogle = [\n            annotation      : 'androidx.annotation:annotation:1.1.0',\n            supportv4       : 'androidx.legacy:legacy-support-v4:1.0.0',\n            appcompat       : 'androidx.appcompat:appcompat:1.2.0',\n            design          : 'com.google.android.material:material:1.0.0',\n            recyclerView    : 'androidx.recyclerview:recyclerview:1.0.0',\n            constraintlayout: 'androidx.constraintlayout:constraintlayout:1.1.3',\n            multidex        : 'androidx.multidex:multidex:2.0.0',\n    ]\n\n    dependenciesOther = [\n            //颜色选择器\n            \"colorpicker\": 'com.github.duanhong169:colorpicker:1.1.6',\n            \"xpopup\"     : 'com.lxj:xpopup:2.2.19'\n    ]\n\n    dependenciesDebug = [\n            \"leakcanary\": \"com.squareup.leakcanary:leakcanary-android:2.5\",\n    ]\n\n}"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Fri Aug 20 09:04:58 CST 2021\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.1.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app\"s APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "mlkit-scanner/.gitignore",
    "content": "/build"
  },
  {
    "path": "mlkit-scanner/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\ndef versions = rootProject.ext.versions\n\nandroid {\n    compileSdkVersion versions.compileSdkVersion\n    defaultConfig {\n        minSdkVersion versions.minSdkVersion\n        targetSdkVersion versions.targetSdkVersion\n        versionCode versions.versionCode\n        versionName versions.versionName\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: \"libs\", include: [\"*.jar\"])\n    compileOnly 'androidx.appcompat:appcompat:1.1.0'\n\n    compileOnly 'com.google.mlkit:barcode-scanning:17.0.2'\n    compileOnly \"androidx.camera:camera-core:1.0.2\"\n    compileOnly \"androidx.camera:camera-camera2:1.0.2\"\n    compileOnly \"androidx.camera:camera-lifecycle:1.0.2\"\n    compileOnly \"androidx.camera:camera-view:1.0.0-alpha25\"\n\n    compileOnly 'com.google.zxing:core:3.3.3'\n\n}"
  },
  {
    "path": "mlkit-scanner/consumer-rules.pro",
    "content": ""
  },
  {
    "path": "mlkit-scanner/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "mlkit-scanner/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.maning.mlkitscanner\">\n\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n    <uses-permission android:name=\"android.permission.VIBRATE\" />\n    <uses-permission android:name=\"android.permission.FLASHLIGHT\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n\n    <uses-feature android:name=\"android.hardware.camera.any\" />\n    <uses-feature\n        android:name=\"android.hardware.camera.autofocus\"\n        android:required=\"false\" />\n    <uses-feature\n        android:name=\"android.hardware.camera.flash\"\n        android:required=\"false\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:supportsRtl=\"true\">\n\n        <activity\n            android:name=\".scan.ui.ScanPreviewActivity\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/MNScanCaptureTheme\" />\n    </application>\n\n</manifest>"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/MNScanManager.java",
    "content": "package com.maning.mlkitscanner.scan;\n\nimport android.app.Activity;\nimport android.content.Intent;\n\nimport com.maning.mlkitscanner.scan.callback.act.ActResultRequest;\nimport com.maning.mlkitscanner.scan.callback.act.MNScanCallback;\nimport com.maning.mlkitscanner.scan.model.MNScanConfig;\nimport com.maning.mlkitscanner.scan.ui.ScanPreviewActivity;\n\n/**\n * Created by maning on 2017/12/7.\n * 启动扫描的主类\n */\n\npublic class MNScanManager {\n\n    //常量\n    public static final int RESULT_SUCCESS = 0;\n    public static final int RESULT_FAIL = 1;\n    public static final int RESULT_CANCLE = 2;\n    public static final String INTENT_KEY_RESULT_SUCCESS = \"INTENT_KEY_RESULT_SUCCESS\";\n    public static final String INTENT_KEY_RESULT_ERROR = \"INTENT_KEY_RESULT_ERROR\";\n    //是否是调试模式\n    public static final boolean isDebugMode = false;\n\n\n    //跳转传入的数据\n    public static final String INTENT_KEY_CONFIG_MODEL = \"INTENT_KEY_CONFIG_MODEL\";\n\n\n    public static void startScan(Activity activity, MNScanCallback scanCallback) {\n        startScan(activity, null, scanCallback);\n    }\n\n    public static void startScan(Activity activity, MNScanConfig mnScanConfig, MNScanCallback scanCallback) {\n        if (mnScanConfig == null) {\n            mnScanConfig = new MNScanConfig.Builder().builder();\n        }\n        Intent intent = new Intent(activity.getApplicationContext(), ScanPreviewActivity.class);\n        //传递数据\n        intent.putExtra(MNScanManager.INTENT_KEY_CONFIG_MODEL, mnScanConfig);\n        ActResultRequest actResultRequest = new ActResultRequest(activity);\n        actResultRequest.startForResult(intent, scanCallback);\n        activity.overridePendingTransition(mnScanConfig.getActivityOpenAnime(), android.R.anim.fade_out);\n    }\n\n    /**\n     * 关闭当前页面\n     */\n    public static void closeScanPage() {\n        ScanPreviewActivity.closeScanPage();\n    }\n\n    /**\n     * 打开相册扫描图片\n     */\n    public static void openAlbumPage() {\n        ScanPreviewActivity.openAlbumPage();\n    }\n\n    /**\n     * 打开手电筒\n     */\n    public static void openScanLight() {\n        ScanPreviewActivity.openScanLight();\n    }\n\n    /**\n     * 关闭手电筒\n     */\n    public static void closeScanLight() {\n        ScanPreviewActivity.closeScanLight();\n    }\n\n    /**\n     * 手电筒是否开启\n     */\n    public static boolean isLightOn() {\n        return ScanPreviewActivity.isLightOn();\n    }\n\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/analyser/BarcodeAnalyser.java",
    "content": "package com.maning.mlkitscanner.scan.analyser;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.camera.core.ImageAnalysis;\nimport androidx.camera.core.ImageProxy;\nimport androidx.camera.view.PreviewView;\n\nimport com.google.android.gms.tasks.OnCompleteListener;\nimport com.google.android.gms.tasks.OnFailureListener;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.android.gms.tasks.Task;\nimport com.google.mlkit.vision.barcode.BarcodeScanner;\nimport com.google.mlkit.vision.barcode.BarcodeScannerOptions;\nimport com.google.mlkit.vision.barcode.BarcodeScanning;\nimport com.google.mlkit.vision.barcode.common.Barcode;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.maning.mlkitscanner.scan.callback.OnCameraAnalyserCallback;\nimport com.maning.mlkitscanner.scan.utils.ImageUtils;\n\nimport java.util.List;\n\n/**\n * @author : maning\n * @date : 8/18/21\n * @desc :\n */\npublic class BarcodeAnalyser implements ImageAnalysis.Analyzer {\n\n    private OnCameraAnalyserCallback onCameraAnalyserCallback;\n    private final BarcodeScanner barcodeScanner;\n    /**\n     * 是否分析\n     */\n    private volatile boolean isAnalyze = true;\n    private Context context;\n    private PreviewView mPreviewView;\n\n    public BarcodeScanner getBarcodeScanner() {\n        return barcodeScanner;\n    }\n\n    public void setAnalyze(boolean analyze) {\n        isAnalyze = analyze;\n    }\n\n    public void setOnCameraAnalyserCallback(OnCameraAnalyserCallback onCameraAnalyserCallback) {\n        this.onCameraAnalyserCallback = onCameraAnalyserCallback;\n    }\n\n    public BarcodeAnalyser() {\n        BarcodeScannerOptions options = new BarcodeScannerOptions.Builder()\n                .setBarcodeFormats(Barcode.FORMAT_ALL_FORMATS)\n                .build();\n        barcodeScanner = BarcodeScanning.getClient(options);\n    }\n\n    public void setPreviewView(PreviewView mPreviewView) {\n        this.mPreviewView = mPreviewView;\n    }\n\n    private Bitmap cropBitmap(Bitmap bitmap, int cropWidth, int cropHeight) {\n        int w = bitmap.getWidth();\n        int h = bitmap.getHeight();\n        return Bitmap.createBitmap(bitmap, (w - cropWidth) / 2, (h - cropHeight) / 2, cropWidth, cropHeight, null, false);\n    }\n\n    @Override\n    public void analyze(@NonNull final ImageProxy imageProxy) {\n        Bitmap bitmap = null;\n        try {\n            bitmap = ImageUtils.imageProxyToBitmap(imageProxy, imageProxy.getImageInfo().getRotationDegrees());\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        if (mPreviewView != null) {\n            //bitmap转为16：9\n            int height = mPreviewView.getHeight();\n            int width = mPreviewView.getWidth();\n            if (bitmap.getHeight() / (float) bitmap.getWidth() > mPreviewView.getHeight() / (float) mPreviewView.getWidth()) {\n                int newHeight = bitmap.getWidth() * height / width;\n                bitmap = cropBitmap(bitmap, bitmap.getWidth(), newHeight);\n            } else if (bitmap.getHeight() / (float) bitmap.getWidth() < mPreviewView.getHeight() / (float) mPreviewView.getWidth()) {\n                int newWith = bitmap.getHeight() * width / height;\n                bitmap = cropBitmap(bitmap, newWith, bitmap.getHeight());\n            }\n            //大小控制和预览一样\n            bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);\n        }\n        InputImage inputImage = InputImage.fromBitmap(bitmap, 0);\n        //InputImage inputImage = InputImage.fromMediaImage(imageProxy.getImage(), imageProxy.getImageInfo().getRotationDegrees());\n        final Bitmap finalBitmap = bitmap;\n        barcodeScanner.process(inputImage)\n                .addOnSuccessListener(new OnSuccessListener<List<Barcode>>() {\n                    @Override\n                    public void onSuccess(@NonNull List<Barcode> barcodes) {\n                        if (barcodes.size() == 0) {\n                            return;\n                        }\n                        if (!isAnalyze) {\n                            return;\n                        }\n                        isAnalyze = false;\n                        for (Barcode barcode : barcodes) {\n                            Log.i(\"======\", \"barcode-getDisplayValue:\" + barcode.getDisplayValue());\n                            Log.i(\"======\", \"barcode-getRawValue:\" + barcode.getRawValue());\n                        }\n                        if (onCameraAnalyserCallback != null) {\n                            onCameraAnalyserCallback.onSuccess(finalBitmap, barcodes);\n                        }\n                    }\n                })\n                .addOnCompleteListener(new OnCompleteListener<List<Barcode>>() {\n                    @Override\n                    public void onComplete(@NonNull Task<List<Barcode>> task) {\n                        imageProxy.close();\n                    }\n                })\n                .addOnFailureListener(new OnFailureListener() {\n                    @Override\n                    public void onFailure(@NonNull Exception e) {\n                        Log.e(\"======\", \"onFailure---:\" + e.toString());\n                    }\n                });\n    }\n}"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/callback/MNCustomViewBindCallback.java",
    "content": "package com.maning.mlkitscanner.scan.callback;\n\nimport android.view.View;\n\n/**\n * 自定义View回调\n */\npublic interface MNCustomViewBindCallback {\n\n    void onBindView(View customView);\n\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/callback/OnCameraAnalyserCallback.java",
    "content": "package com.maning.mlkitscanner.scan.callback;\n\nimport android.graphics.Bitmap;\n\n\nimport com.google.mlkit.vision.barcode.common.Barcode;\n\nimport java.util.List;\n\n/**\n * @author : maning\n * @date : 8/19/21\n * @desc : 扫码分析结果回调\n */\npublic interface OnCameraAnalyserCallback {\n    void onSuccess(Bitmap bitmap, List<Barcode> barcodes);\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/callback/act/ActResultRequest.java",
    "content": "package com.maning.mlkitscanner.scan.callback.act;\n\nimport android.app.Activity;\nimport android.app.FragmentManager;\nimport android.content.Intent;\n\n/**\n * <pre>\n *     author : maning\n *     e-mail : xxx@xx\n *     time   : 2018/06/04\n *     desc   :\n *     version: 1.0\n * </pre>\n */\npublic class ActResultRequest {\n    private OnActResultEventDispatcherFragment fragment;\n\n    public ActResultRequest(Activity activity) {\n        fragment = getEventDispatchFragment(activity);\n    }\n\n    private OnActResultEventDispatcherFragment getEventDispatchFragment(Activity activity) {\n        final FragmentManager fragmentManager = activity.getFragmentManager();\n\n        OnActResultEventDispatcherFragment fragment = findEventDispatchFragment(fragmentManager);\n        if (fragment == null) {\n            fragment = new OnActResultEventDispatcherFragment();\n            fragmentManager\n                    .beginTransaction()\n                    .add(fragment, OnActResultEventDispatcherFragment.TAG)\n                    .commitAllowingStateLoss();\n            fragmentManager.executePendingTransactions();\n        }\n        return fragment;\n    }\n\n    private OnActResultEventDispatcherFragment findEventDispatchFragment(FragmentManager manager) {\n        return (OnActResultEventDispatcherFragment) manager.findFragmentByTag(OnActResultEventDispatcherFragment.TAG);\n    }\n\n    public void startForResult(Intent intent, MNScanCallback callback) {\n        fragment.startForResult(intent, callback);\n    }\n\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/callback/act/MNScanCallback.java",
    "content": "package com.maning.mlkitscanner.scan.callback.act;\n\nimport android.content.Intent;\n\n/**\n * <pre>\n *     author : maning\n *     e-mail : xxx@xx\n *     time   : 2018/06/04\n *     desc   :\n *     version: 1.0\n * </pre>\n */\npublic interface MNScanCallback {\n\n    void onActivityResult(int resultCode, Intent data);\n\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/callback/act/OnActResultEventDispatcherFragment.java",
    "content": "package com.maning.mlkitscanner.scan.callback.act;\n\nimport android.app.Fragment;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.SparseArray;\n\n/**\n * <pre>\n *     author : maning\n *     e-mail : xxx@xx\n *     time   : 2018/06/04\n *     desc   :\n *     version: 1.0\n * </pre>\n */\npublic class OnActResultEventDispatcherFragment extends Fragment {\n    public static final String TAG = \"on_act_result_event_dispatcher\";\n\n    private SparseArray<MNScanCallback> mCallbacks = new SparseArray<>();\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRetainInstance(true);\n    }\n\n    public void startForResult(Intent intent, MNScanCallback callback) {\n        mCallbacks.put(callback.hashCode(), callback);\n        startActivityForResult(intent, callback.hashCode());\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n\n        MNScanCallback callback = mCallbacks.get(requestCode);\n        mCallbacks.remove(requestCode);\n\n        if (callback != null) {\n            callback.onActivityResult(resultCode, data);\n        }\n    }\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/camera/CameraManager.java",
    "content": "package com.maning.mlkitscanner.scan.camera;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.view.MotionEvent;\nimport android.view.ScaleGestureDetector;\nimport android.view.View;\n\nimport androidx.camera.core.Camera;\nimport androidx.camera.core.CameraSelector;\nimport androidx.camera.core.FocusMeteringAction;\nimport androidx.camera.core.ImageAnalysis;\nimport androidx.camera.core.MeteringPoint;\nimport androidx.camera.core.Preview;\nimport androidx.camera.core.ZoomState;\nimport androidx.camera.lifecycle.ProcessCameraProvider;\nimport androidx.camera.view.PreviewView;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.LifecycleOwner;\n\nimport com.google.common.util.concurrent.ListenableFuture;\nimport com.google.mlkit.vision.barcode.common.Barcode;\nimport com.maning.mlkitscanner.scan.analyser.BarcodeAnalyser;\nimport com.maning.mlkitscanner.scan.callback.OnCameraAnalyserCallback;\nimport com.maning.mlkitscanner.scan.model.MNScanConfig;\nimport com.maning.mlkitscanner.scan.utils.BeepManager;\n\nimport java.util.List;\nimport java.util.concurrent.Executors;\n\n/**\n * @author : maning\n * @date : 8/19/21\n * @desc :\n */\npublic class CameraManager {\n\n    private static final int HOVER_TAP_TIMEOUT = 150;\n    private static final int HOVER_TAP_SLOP = 20;\n\n    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;\n    private LifecycleOwner mLifecycleOwner;\n    private Camera mCamera;\n    private long mLastHoveTapTime;\n    private boolean isClickTap;\n    private float mDownX;\n    private float mDownY;\n    private PreviewView mPreviewView;\n    private Context mContext;\n    private BarcodeAnalyser barcodeAnalyser;\n    private OnCameraAnalyserCallback onCameraAnalyserCallback;\n    private MNScanConfig scanConfig;\n    private BeepManager beepManager;\n\n    public static CameraManager getInstance(Context mContext, PreviewView mPreviewView) {\n        return new CameraManager(mContext, mPreviewView);\n    }\n\n    public CameraManager(Context mContext, PreviewView mPreviewView) {\n        this.mContext = mContext;\n        this.mPreviewView = mPreviewView;\n        initDatas();\n    }\n\n    public BarcodeAnalyser getBarcodeAnalyser() {\n        return barcodeAnalyser;\n    }\n\n    public void setOnCameraAnalyserCallback(OnCameraAnalyserCallback callback) {\n        this.onCameraAnalyserCallback = callback;\n    }\n\n    public void setScanConfig(MNScanConfig config) {\n        scanConfig = config;\n        beepManager.setPlayBeep(scanConfig.isShowBeep());\n        beepManager.setVibrate(scanConfig.isShowVibrate());\n    }\n\n    public void setAnalyze(boolean analyze) {\n        barcodeAnalyser.setAnalyze(analyze);\n    }\n\n    private void initDatas() {\n        mLifecycleOwner = (LifecycleOwner) mContext;\n        beepManager = new BeepManager(mContext);\n        initBarcodeAnalyser();\n        initScaleGesture();\n    }\n\n    public void startCamera() {\n        cameraProviderFuture = ProcessCameraProvider.getInstance(mContext);\n        cameraProviderFuture.addListener(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    ProcessCameraProvider cameraProvider = cameraProviderFuture.get();\n                    Preview preview = new Preview.Builder().build();\n                    //绑定预览\n                    preview.setSurfaceProvider(mPreviewView.getSurfaceProvider());\n                    //使用后置相机\n                    CameraSelector cameraSelector = new CameraSelector.Builder()\n                            .requireLensFacing(CameraSelector.LENS_FACING_BACK)\n                            .build();\n                    //配置图片扫描\n                    ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()\n                            .setTargetResolution(CameraSizeUtils.getSize(mContext))\n                            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)\n                            .build();\n                    imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), barcodeAnalyser);\n                    if (mCamera != null) {\n                        cameraProviderFuture.get().unbindAll();\n                    }\n                    //将相机绑定到当前控件的生命周期\n                    mCamera = cameraProvider.bindToLifecycle(mLifecycleOwner, cameraSelector, imageAnalysis, preview);\n                } catch (Exception e) {\n                }\n            }\n        }, ContextCompat.getMainExecutor(mContext));\n    }\n\n    private void initBarcodeAnalyser() {\n        barcodeAnalyser = new BarcodeAnalyser();\n        barcodeAnalyser.setPreviewView(mPreviewView);\n        barcodeAnalyser.setAnalyze(true);\n        barcodeAnalyser.setOnCameraAnalyserCallback(new OnCameraAnalyserCallback() {\n            @Override\n            public void onSuccess(Bitmap bitmap, List<Barcode> barcodes) {\n                beepManager.playBeepSoundAndVibrate();\n                if (onCameraAnalyserCallback != null) {\n                    onCameraAnalyserCallback.onSuccess(bitmap, barcodes);\n                }\n            }\n        });\n    }\n\n    private void initScaleGesture() {\n        ScaleGestureDetector scaleGestureDetector = new ScaleGestureDetector(mContext, mOnScaleGestureListener);\n        mPreviewView.setOnTouchListener(new View.OnTouchListener() {\n            @Override\n            public boolean onTouch(View view, MotionEvent event) {\n                handlePreviewViewClickTap(event);\n                if (scanConfig != null && scanConfig.isSupportZoom()) {\n                    return scaleGestureDetector.onTouchEvent(event);\n                }\n                return false;\n            }\n        });\n    }\n\n    private ScaleGestureDetector.OnScaleGestureListener mOnScaleGestureListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() {\n        @Override\n        public boolean onScale(ScaleGestureDetector detector) {\n            float scale = detector.getScaleFactor();\n            if (mCamera != null) {\n                float ratio = mCamera.getCameraInfo().getZoomState().getValue().getZoomRatio();\n                zoomTo(ratio * scale);\n            }\n            return true;\n        }\n\n    };\n\n    private void handlePreviewViewClickTap(MotionEvent event) {\n        if (event.getPointerCount() == 1) {\n            switch (event.getAction()) {\n                case MotionEvent.ACTION_DOWN:\n                    isClickTap = true;\n                    mDownX = event.getX();\n                    mDownY = event.getY();\n                    mLastHoveTapTime = System.currentTimeMillis();\n                    break;\n                case MotionEvent.ACTION_MOVE:\n                    isClickTap = distance(mDownX, mDownY, event.getX(), event.getY()) < HOVER_TAP_SLOP;\n                    break;\n                case MotionEvent.ACTION_UP:\n                    if (isClickTap && mLastHoveTapTime + HOVER_TAP_TIMEOUT > System.currentTimeMillis()) {\n                        startFocusAndMetering(event.getX(), event.getY());\n                    }\n                    break;\n            }\n        }\n    }\n\n    private float distance(float aX, float aY, float bX, float bY) {\n        float xDiff = aX - bX;\n        float yDiff = aY - bY;\n        return (float) Math.sqrt(xDiff * xDiff + yDiff * yDiff);\n    }\n\n    public void zoomTo(float ratio) {\n        if (mCamera != null) {\n            ZoomState zoomState = mCamera.getCameraInfo().getZoomState().getValue();\n            float maxRatio = zoomState.getMaxZoomRatio();\n            float minRatio = zoomState.getMinZoomRatio();\n            float zoom = Math.max(Math.min(ratio, maxRatio), minRatio);\n            mCamera.getCameraControl().setZoomRatio(zoom);\n        }\n    }\n\n    private void startFocusAndMetering(float x, float y) {\n        if (mCamera != null) {\n            MeteringPoint point = mPreviewView.getMeteringPointFactory().createPoint(x, y);\n            mCamera.getCameraControl().startFocusAndMetering(new FocusMeteringAction.Builder(point).build());\n        }\n    }\n\n    public void openLight() {\n        if (mCamera != null) {\n            mCamera.getCameraControl().enableTorch(true);\n        }\n    }\n\n    public void closeLight() {\n        if (mCamera != null) {\n            mCamera.getCameraControl().enableTorch(false);\n        }\n    }\n\n    public void stopCamera() {\n        try {\n            if (cameraProviderFuture != null) {\n                cameraProviderFuture.get().unbindAll();\n            }\n        } catch (Exception e) {\n        }\n    }\n\n    public void release() {\n        try {\n            mPreviewView = null;\n            mLifecycleOwner = null;\n            stopCamera();\n        } catch (Exception e) {\n        }\n    }\n\n} "
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/camera/CameraSizeUtils.java",
    "content": "package com.maning.mlkitscanner.scan.camera;\n\nimport android.content.Context;\nimport android.util.DisplayMetrics;\nimport android.util.Log;\nimport android.util.Size;\n\n/**\n * @author : maning\n * @date : 8/19/21\n * @desc :\n */\npublic class CameraSizeUtils {\n\n    public static Size getSize(Context context) {\n        Size mTargetSize;\n        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();\n        int width = displayMetrics.widthPixels;\n        int height = displayMetrics.heightPixels;\n        Log.i(\"======\", String.format(\"displayMetrics:%d x %d\", width, height));\n        //因为为了保持流畅性和性能，限制在1080p，在此前提下尽可能的找到屏幕接近的分辨率\n        if (width < height) {\n            int size = Math.min(width, 1080);\n            float ratio = width / (float) height;\n            if (ratio > 0.7) {//一般应用于平板\n                mTargetSize = new Size(size, (int) (size / 3.0f * 4.0f));\n            } else {\n                mTargetSize = new Size(size, (int) (size / 9.0f * 16.0f));\n            }\n        } else {\n            int size = Math.min(height, 1080);\n            float ratio = height / (float) width;\n            if (ratio > 0.7) {//一般应用于平板\n                mTargetSize = new Size((int) (size / 3.0f * 4.0f), size);\n            } else {\n                mTargetSize = new Size((int) (size / 9.0f * 16.0), size);\n            }\n        }\n        Log.i(\"======\", \"mTargetSize:\" + mTargetSize.getWidth() + \",\" + mTargetSize.getHeight());\n        return mTargetSize;\n    }\n\n} "
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/model/MNScanConfig.java",
    "content": "package com.maning.mlkitscanner.scan.model;\n\n\nimport com.maning.mlkitscanner.R;\nimport com.maning.mlkitscanner.scan.callback.MNCustomViewBindCallback;\n\nimport java.io.Serializable;\n\n/**\n * Created by maning on 2017/12/7.\n * 启动Activity的一些配置参数\n */\n\npublic class MNScanConfig implements Serializable {\n\n    private static final long serialVersionUID = -5260676142223049891L;\n\n    public static MNCustomViewBindCallback mCustomViewBindCallback;\n\n    //枚举类型：扫描线样式\n    public enum LaserStyle {\n        Line,\n        Grid,\n    }\n\n    //是否显示相册\n    private boolean showPhotoAlbum;\n    //扫描声音\n    private boolean showBeep;\n    //扫描震动\n    private boolean showVibrate;\n    //扫描框和扫描线的颜色\n    private String scanColor;\n    //扫描线的样式\n    private LaserStyle laserStyle;\n    //扫描提示文案\n    private String scanHintText;\n    //扫描提示文案颜色\n    private String scanHintTextColor;\n    //扫描提示文案字体大小\n    private int scanHintTextSize;\n    //开启Activity动画\n    private int activityOpenAnime;\n    //关闭Activity动画\n    private int activityExitAnime;\n    //是否支持手势缩放，默认支持\n    private boolean isSupportZoom = true;\n    //自定义View\n    private int customShadeViewLayoutID;\n    //扫描背景色\n    private String bgColor;\n    //网格扫描线的列数\n    private int gridScanLineColumn;\n    //网格扫描线的高度\n    private int gridScanLineHeight;\n    //显示闪光灯\n    private boolean showLightController = true;\n    //是否需要全屏扫描，默认全屏扫描\n    private boolean isFullScreenScan = true;\n    //扫描二维码中心点宽高\n    private int resultPointWithdHeight = 0;\n    //扫描二维码中心点显示圆角\n    private int resultPointCorners = 0;\n    //扫描二维码中心点显示描边\n    private int resultPointStrokeWidth = 0;\n    //扫描二维码中心点显示描边颜色\n    private String resultPointStrokeColor;\n    //扫描二维码中心点显示颜色\n    private String resultPointColor;\n    //状态栏颜色\n    private String statusBarColor = \"#00000000\";\n    //状态栏是否显示黑色字体\n    private boolean statusBarDarkMode = false;\n    //扫描框宽度大小比例，非全屏模式下生效，默认0.7，范围0.5-0.9\n    private float scanFrameSizeScale = 0.7f;\n\n    private MNScanConfig() {\n\n    }\n\n\n    private MNScanConfig(Builder builder) {\n        showPhotoAlbum = builder.showPhotoAlbum;\n        showBeep = builder.showBeep;\n        showVibrate = builder.showVibrate;\n        scanColor = builder.scanColor;\n        laserStyle = builder.laserStyle;\n        scanHintText = builder.scanHintText;\n        activityOpenAnime = builder.activityOpenAnime;\n        activityExitAnime = builder.activityExitAnime;\n        customShadeViewLayoutID = builder.customShadeViewLayoutID;\n        bgColor = builder.bgColor;\n        gridScanLineColumn = builder.gridScanLineColumn;\n        gridScanLineHeight = builder.gridScanLineHeight;\n        showLightController = builder.showLightController;\n        scanHintTextColor = builder.scanHintTextColor;\n        scanHintTextSize = builder.scanHintTextSize;\n        isFullScreenScan = builder.isFullScreenScan;\n        isSupportZoom = builder.isSupportZoom;\n        resultPointWithdHeight = builder.resultPointWithdHeight;\n        resultPointCorners = builder.resultPointCorners;\n        resultPointStrokeWidth = builder.resultPointStrokeWidth;\n        resultPointStrokeColor = builder.resultPointStrokeColor;\n        resultPointColor = builder.resultPointColor;\n        statusBarColor = builder.statusBarColor;\n        statusBarDarkMode = builder.statusBarDarkMode;\n        scanFrameSizeScale = builder.scanFrameSizeScale;\n\n    }\n\n    public String getStatusBarColor() {\n        return statusBarColor;\n    }\n\n    public boolean isStatusBarDarkMode() {\n        return statusBarDarkMode;\n    }\n\n    public int getResultPointWithdHeight() {\n        return resultPointWithdHeight;\n    }\n\n    public int getResultPointCorners() {\n        return resultPointCorners;\n    }\n\n    public int getResultPointStrokeWidth() {\n        return resultPointStrokeWidth;\n    }\n\n    public String getResultPointStrokeColor() {\n        return resultPointStrokeColor;\n    }\n\n    public String getResultPointColor() {\n        return resultPointColor;\n    }\n\n    public boolean isShowPhotoAlbum() {\n        return showPhotoAlbum;\n    }\n\n    public boolean isShowBeep() {\n        return showBeep;\n    }\n\n    public boolean isShowVibrate() {\n        return showVibrate;\n    }\n\n    public String getScanColor() {\n        return scanColor;\n    }\n\n    public LaserStyle getLaserStyle() {\n        return laserStyle;\n    }\n\n    public String getScanHintText() {\n        return scanHintText;\n    }\n\n    public String getScanHintTextColor() {\n        return scanHintTextColor;\n    }\n\n    public int getScanHintTextSize() {\n        return scanHintTextSize;\n    }\n\n    public int getActivityOpenAnime() {\n        return activityOpenAnime;\n    }\n\n    public int getActivityExitAnime() {\n        return activityExitAnime;\n    }\n\n    public int getCustomShadeViewLayoutID() {\n        return customShadeViewLayoutID;\n    }\n\n    public String getBgColor() {\n        return bgColor;\n    }\n\n    public int getGridScanLineColumn() {\n        return gridScanLineColumn;\n    }\n\n    public int getGridScanLineHeight() {\n        return gridScanLineHeight;\n    }\n\n    public boolean isShowLightController() {\n        return showLightController;\n    }\n\n    public boolean isFullScreenScan() {\n        return isFullScreenScan;\n    }\n\n    public boolean isSupportZoom() {\n        return isSupportZoom;\n    }\n\n    public float getScanFrameSizeScale() {\n        if (scanFrameSizeScale > 0.9) {\n            scanFrameSizeScale = 0.9f;\n        }\n        if (scanFrameSizeScale < 0.5) {\n            scanFrameSizeScale = 0.5f;\n        }\n        return scanFrameSizeScale;\n    }\n\n    public static class Builder {\n        private boolean showPhotoAlbum = true;\n        private boolean showBeep = true;\n        private boolean showVibrate = true;\n        //扫描颜色\n        private String scanColor;\n        private String bgColor;\n        private LaserStyle laserStyle = LaserStyle.Line;\n        private int activityOpenAnime = R.anim.mn_scan_activity_bottom_in;\n        private int activityExitAnime = R.anim.mn_scan_activity_bottom_out;\n        private int customShadeViewLayoutID;\n        //网格扫描线的列数\n        private int gridScanLineColumn;\n        //网格扫描线的高度\n        private int gridScanLineHeight;\n        //闪光灯\n        private boolean showLightController = true;\n        //扫描提示文案\n        private String scanHintText = \"扫二维码/条形码\";\n        //扫描提示文案颜色\n        private String scanHintTextColor;\n        //扫描提示文案字体大小\n        private int scanHintTextSize;\n        //是否需要全屏扫描，默认值扫描扫描框中的二维码\n        private boolean isFullScreenScan = true;\n        //是否支持手势缩放，默认支持\n        private boolean isSupportZoom = true;\n        //扫描二维码中心点显示半径\n        private int resultPointWithdHeight = 0;\n        //扫描二维码中心点显示圆角\n        private int resultPointCorners = 0;\n        //扫描二维码中心点显示描边\n        private int resultPointStrokeWidth = 0;\n        //扫描二维码中心点显示描边颜色\n        private String resultPointStrokeColor;\n        //扫描二维码中心点显示颜色\n        private String resultPointColor;\n        //状态栏颜色\n        private String statusBarColor = \"#00000000\";\n        //状态栏是否显示黑色字体\n        private boolean statusBarDarkMode = false;\n        //扫描框宽度大小比例，非全屏模式下生效，默认0.7，范围0.5-0.9\n        private float scanFrameSizeScale = 0.7f;\n\n        public MNScanConfig builder() {\n            return new MNScanConfig(this);\n        }\n\n        public Builder setStatusBarConfigs(String statusBarColor,\n                                           boolean statusBarDarkMode) {\n            this.statusBarColor = statusBarColor;\n            this.statusBarDarkMode = statusBarDarkMode;\n            return this;\n        }\n\n        /**\n         * 设置扫描点大小圆角等（单位dp）\n         *\n         * @param resultPointWithdHeight\n         * @param resultPointCorners\n         * @param resultPointStrokeWidth\n         * @param resultPointStrokeColor\n         * @param resultPointColor\n         * @return\n         */\n        public Builder setResultPointConfigs(int resultPointWithdHeight,\n                                             int resultPointCorners,\n                                             int resultPointStrokeWidth,\n                                             String resultPointStrokeColor,\n                                             String resultPointColor) {\n            this.resultPointWithdHeight = resultPointWithdHeight;\n            this.resultPointCorners = resultPointCorners;\n            this.resultPointStrokeWidth = resultPointStrokeWidth;\n            this.resultPointStrokeColor = resultPointStrokeColor;\n            this.resultPointColor = resultPointColor;\n            return this;\n        }\n\n        public Builder setLaserStyle(LaserStyle laserStyle) {\n            this.laserStyle = laserStyle;\n            return this;\n        }\n\n        public Builder isShowPhotoAlbum(boolean showPhotoAlbum) {\n            this.showPhotoAlbum = showPhotoAlbum;\n            return this;\n        }\n\n        public Builder isShowBeep(boolean showBeep) {\n            this.showBeep = showBeep;\n            return this;\n        }\n\n        public Builder isShowVibrate(boolean showVibrate) {\n            this.showVibrate = showVibrate;\n            return this;\n        }\n\n        public Builder setScanColor(String scanColor) {\n            this.scanColor = scanColor;\n            return this;\n        }\n\n        public Builder setScanHintText(String scanHintText) {\n            this.scanHintText = scanHintText;\n            return this;\n        }\n\n        public Builder setActivityOpenAnime(int activityOpenAnime) {\n            this.activityOpenAnime = activityOpenAnime;\n            return this;\n        }\n\n        public Builder setActivityExitAnime(int activityExitAnime) {\n            this.activityExitAnime = activityExitAnime;\n            return this;\n        }\n\n        public Builder setCustomShadeViewLayoutID(int customShadeViewLayoutID, MNCustomViewBindCallback mnCustomViewBindCallback) {\n            this.customShadeViewLayoutID = customShadeViewLayoutID;\n            mCustomViewBindCallback = mnCustomViewBindCallback;\n            return this;\n        }\n\n        public Builder setBgColor(String bgColor) {\n            this.bgColor = bgColor;\n            return this;\n        }\n\n        public Builder setGridScanLineColumn(int gridScanLineColumn) {\n            this.gridScanLineColumn = gridScanLineColumn;\n            return this;\n        }\n\n        public Builder setGridScanLineHeight(int gridScanLineHeight) {\n            this.gridScanLineHeight = gridScanLineHeight;\n            return this;\n        }\n\n        public Builder isShowLightController(boolean showLightController) {\n            this.showLightController = showLightController;\n            return this;\n        }\n\n        public Builder setScanHintTextColor(String scanHintTextColor) {\n            this.scanHintTextColor = scanHintTextColor;\n            return this;\n        }\n\n        public Builder setScanHintTextSize(int scanHintTextSize) {\n            this.scanHintTextSize = scanHintTextSize;\n            return this;\n        }\n\n        public Builder setFullScreenScan(boolean fullScreenScan) {\n            isFullScreenScan = fullScreenScan;\n            return this;\n        }\n\n        public Builder setSupportZoom(boolean supportZoom) {\n            isSupportZoom = supportZoom;\n            return this;\n        }\n\n        public Builder setScanFrameSizeScale(float widthScale) {\n            scanFrameSizeScale = widthScale;\n            return this;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/ui/ScanPreviewActivity.java",
    "content": "package com.maning.mlkitscanner.scan.ui;\n\nimport android.Manifest;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.WindowManager;\nimport android.widget.RelativeLayout;\nimport android.widget.Toast;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.camera.view.PreviewView;\n\nimport com.google.android.gms.tasks.OnFailureListener;\nimport com.google.android.gms.tasks.OnSuccessListener;\nimport com.google.mlkit.vision.barcode.common.Barcode;\nimport com.google.mlkit.vision.common.InputImage;\nimport com.maning.mlkitscanner.R;\nimport com.maning.mlkitscanner.scan.MNScanManager;\nimport com.maning.mlkitscanner.scan.callback.OnCameraAnalyserCallback;\nimport com.maning.mlkitscanner.scan.camera.CameraManager;\nimport com.maning.mlkitscanner.scan.model.MNScanConfig;\nimport com.maning.mlkitscanner.scan.utils.BeepManager;\nimport com.maning.mlkitscanner.scan.utils.ImageUtils;\nimport com.maning.mlkitscanner.scan.utils.StatusBarUtil;\nimport com.maning.mlkitscanner.scan.view.ScanActionMenuView;\nimport com.maning.mlkitscanner.scan.view.ScanResultPointView;\nimport com.maning.mlkitscanner.scan.view.ViewfinderView;\n\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ScanPreviewActivity extends AppCompatActivity {\n\n    //用来保存当前Activity\n    private static WeakReference<ScanPreviewActivity> sActivityRef;\n    private static final int REQUEST_CODE_PICK_IMAGE = 10010;\n    private static final int REQUEST_CODE_PERMISSION_CAMERA = 10011;\n    private static final int REQUEST_CODE_PERMISSION_STORAGE = 10012;\n    private Context mContext;\n    //闪光灯是否打开\n    private boolean is_light_on = false;\n    private MNScanConfig mScanConfig;\n\n    private CameraManager cameraManager;\n    private View fakeStatusBar;\n    private PreviewView mPreviewView;\n    private ViewfinderView viewfinderView;\n    private ScanResultPointView result_point_view;\n    private ScanActionMenuView action_menu_view;\n    private RelativeLayout rl_act_root;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);\n        setContentView(R.layout.mn_scan_activity_scan_preview);\n        mContext = this;\n        sActivityRef = new WeakReference<>(this);\n        initConfig();\n        initViews();\n        initCamera();\n        initStatusBar();\n        initPermission();\n    }\n\n\n    private void initStatusBar() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            StatusBarUtil.setTransparentForWindow(this);\n            int statusBarHeight = StatusBarUtil.getStatusBarHeight(mContext);\n            ViewGroup.LayoutParams fakeStatusBarLayoutParams = fakeStatusBar.getLayoutParams();\n            fakeStatusBarLayoutParams.height = statusBarHeight;\n            fakeStatusBar.setLayoutParams(fakeStatusBarLayoutParams);\n            //状态栏文字颜色\n            if (mScanConfig.isStatusBarDarkMode()) {\n                StatusBarUtil.setDarkMode(this);\n            }\n            //状态栏颜色\n            String statusBarColor = mScanConfig.getStatusBarColor();\n            fakeStatusBar.setBackgroundColor(Color.parseColor(statusBarColor));\n        } else {\n            ViewGroup.LayoutParams fakeStatusBarLayoutParams = fakeStatusBar.getLayoutParams();\n            fakeStatusBarLayoutParams.height = 0;\n            fakeStatusBar.setLayoutParams(fakeStatusBarLayoutParams);\n        }\n    }\n\n    private void initPermission() {\n        //检查相机权限\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {\n                //没有相机权限\n                requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_PERMISSION_CAMERA);\n            } else {\n                startCamera();\n            }\n        } else {\n            startCamera();\n        }\n    }\n\n    private void initCamera() {\n        cameraManager = CameraManager.getInstance(sActivityRef.get(), mPreviewView);\n        cameraManager.setScanConfig(mScanConfig);\n        cameraManager.setOnCameraAnalyserCallback(new OnCameraAnalyserCallback() {\n            @Override\n            public void onSuccess(Bitmap bitmap, List<Barcode> barcodes) {\n                result_point_view.setDatas(barcodes, bitmap);\n                result_point_view.setVisibility(View.VISIBLE);\n                if (barcodes.size() == 1) {\n                    finishSuccess(barcodes.get(0).getDisplayValue());\n                }\n            }\n        });\n    }\n\n    private void startCamera() {\n        cameraManager.startCamera();\n    }\n\n    private void initConfig() {\n        mScanConfig = (MNScanConfig) getIntent().getSerializableExtra(MNScanManager.INTENT_KEY_CONFIG_MODEL);\n        if (mScanConfig == null) {\n            mScanConfig = new MNScanConfig.Builder().builder();\n        }\n    }\n\n    private void initViews() {\n        rl_act_root = (RelativeLayout) findViewById(R.id.rl_act_root);\n        mPreviewView = (PreviewView) findViewById(R.id.previewView);\n        mPreviewView.setScaleType(PreviewView.ScaleType.FILL_CENTER);\n        fakeStatusBar = (View) findViewById(R.id.fakeStatusBar);\n        viewfinderView = (ViewfinderView) findViewById(R.id.viewfinderView);\n        action_menu_view = (ScanActionMenuView) findViewById(R.id.action_menu_view);\n        result_point_view = (ScanResultPointView) findViewById(R.id.result_point_view);\n\n        action_menu_view.setOnScanActionMenuListener(new ScanActionMenuView.OnScanActionMenuListener() {\n            @Override\n            public void onClose() {\n                finishCancle();\n            }\n\n            @Override\n            public void onLight() {\n                if (is_light_on) {\n                    closeLight();\n                } else {\n                    openLight();\n                }\n            }\n\n            @Override\n            public void onPhoto() {\n                getImageFromAlbum();\n            }\n        });\n\n        result_point_view.setOnResultPointClickListener(new ScanResultPointView.OnResultPointClickListener() {\n            @Override\n            public void onPointClick(String result) {\n                finishSuccess(result);\n            }\n\n            @Override\n            public void onCancle() {\n                cameraManager.setAnalyze(true);\n                result_point_view.removeAllPoints();\n                result_point_view.setVisibility(View.GONE);\n            }\n        });\n\n        viewfinderView.setScanConfig(mScanConfig);\n        result_point_view.setScanConfig(mScanConfig);\n        action_menu_view.setScanConfig(mScanConfig, MNScanConfig.mCustomViewBindCallback);\n    }\n\n    private void openLight() {\n        if (!is_light_on) {\n            is_light_on = true;\n            action_menu_view.openLight();\n            cameraManager.openLight();\n        }\n    }\n\n    private void closeLight() {\n        if (is_light_on) {\n            is_light_on = false;\n            action_menu_view.closeLight();\n            cameraManager.closeLight();\n        }\n    }\n\n    /**\n     * 获取相册中的图片\n     */\n    public void getImageFromAlbum() {\n        if (checkStoragePermission()) {\n            Intent intent = new Intent();\n            intent.setAction(Intent.ACTION_PICK);\n            intent.setType(\"image/*\");\n            startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);\n        }\n    }\n\n    private boolean checkStoragePermission() {\n        //判断权限\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {\n                requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_CODE_PERMISSION_STORAGE);\n                return false;\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        switch (requestCode) {\n            case REQUEST_CODE_PERMISSION_CAMERA:\n                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                    // Permission Granted 授予权限\n                    //用户同意了权限申请\n                    startCamera();\n                } else {\n                    // Permission Denied 权限被拒绝\n                    Toast.makeText(mContext, \"初始化相机失败,相机权限被拒绝\", Toast.LENGTH_SHORT).show();\n                    finishFailed(\"初始化相机失败,相机权限被拒绝\");\n                }\n                break;\n            case REQUEST_CODE_PERMISSION_STORAGE:\n                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                    //用户同意使用write\n                    getImageFromAlbum();\n                } else {\n                    //缺少权限\n                    Toast.makeText(mContext, \"打开相册失败,读写权限被拒绝\", Toast.LENGTH_SHORT).show();\n                }\n            default:\n                break;\n        }\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        //去相册选择图片\n        if (requestCode == REQUEST_CODE_PICK_IMAGE && resultCode == RESULT_OK) {\n            if (data == null) {\n                return;\n            }\n            Bitmap decodeAbleBitmap = ImageUtils.getBitmap(mContext, data.getData());\n            if (decodeAbleBitmap == null) {\n                Log.e(\"======\", \"decodeAbleBitmap == null\");\n                return;\n            }\n            cameraManager.setAnalyze(false);\n            new Thread(new Runnable() {\n                @Override\n                public void run() {\n                    //分析这个图片\n                    InputImage inputImage = InputImage.fromBitmap(decodeAbleBitmap, 0);\n                    cameraManager.getBarcodeAnalyser().getBarcodeScanner().process(inputImage)\n                            .addOnSuccessListener(new OnSuccessListener<List<Barcode>>() {\n                                @Override\n                                public void onSuccess(@NonNull List<Barcode> barcodes) {\n                                    runOnUiThread(new Runnable() {\n                                        @Override\n                                        public void run() {\n                                            Log.e(\"======\", \"barcodes.size():\" + barcodes.size());\n                                            if (barcodes.size() == 0) {\n                                                cameraManager.setAnalyze(true);\n                                                Toast.makeText(mContext, \"未找到二维码或者条形码\", Toast.LENGTH_SHORT).show();\n                                                return;\n                                            }\n                                            ArrayList<String> results = new ArrayList<>();\n                                            for (Barcode barcode : barcodes) {\n                                                String value = barcode.getDisplayValue();\n                                                Log.e(\"======\", \"value:\" + value);\n                                                results.add(value);\n                                            }\n\n                                            finishSuccess(results);\n                                        }\n                                    });\n                                }\n                            })\n                            .addOnFailureListener(new OnFailureListener() {\n                                @Override\n                                public void onFailure(@NonNull Exception e) {\n                                    Log.e(\"======\", \"onFailure---:\" + e.toString());\n                                }\n                            });\n                }\n            }).start();\n        }\n    }\n\n\n    @Override\n    public void onBackPressed() {\n        if (result_point_view.getVisibility() == View.VISIBLE) {\n            cameraManager.setAnalyze(true);\n            result_point_view.removeAllPoints();\n            result_point_view.setVisibility(View.GONE);\n            return;\n        }\n        //取消扫码\n        finishCancle();\n    }\n\n    @Override\n    protected void onDestroy() {\n        cameraManager.release();\n        super.onDestroy();\n    }\n\n    private void finishCancle() {\n        setResult(MNScanManager.RESULT_CANCLE, new Intent());\n        finishFinal();\n    }\n\n    private void finishFailed(String errorMsg) {\n        Intent intent = new Intent();\n        intent.putExtra(MNScanManager.INTENT_KEY_RESULT_ERROR, errorMsg);\n        setResult(MNScanManager.RESULT_FAIL, intent);\n        finishFinal();\n    }\n\n    private void finishSuccess(String result) {\n        ArrayList<String> results = new ArrayList<>();\n        results.add(result);\n        finishSuccess(results);\n    }\n\n    private void finishSuccess(ArrayList<String> results) {\n        Intent intent = new Intent();\n        intent.putStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS, results);\n        setResult(MNScanManager.RESULT_SUCCESS, intent);\n        finishFinal();\n    }\n\n    private void finishFinal() {\n        closeLight();\n        MNScanConfig.mCustomViewBindCallback = null;\n        sActivityRef = null;\n        viewfinderView.destroyView();\n        cameraManager.release();\n        rl_act_root.removeView(viewfinderView);\n        rl_act_root.removeView(mPreviewView);\n        rl_act_root.removeView(action_menu_view);\n        finish();\n        overridePendingTransition(0, mScanConfig.getActivityExitAnime() == 0 ? R.anim.mn_scan_activity_bottom_out : mScanConfig.getActivityExitAnime());\n    }\n\n    //---------对外提供方法----------\n\n    /**\n     * 关闭当前Activity\n     */\n    public static void closeScanPage() {\n        if (sActivityRef != null && sActivityRef.get() != null) {\n            sActivityRef.get().finishCancle();\n        }\n    }\n\n    /**\n     * 打开相册扫描图片\n     */\n    public static void openAlbumPage() {\n        if (sActivityRef != null && sActivityRef.get() != null) {\n            sActivityRef.get().getImageFromAlbum();\n        }\n    }\n\n    /**\n     * 打开手电筒\n     */\n    public static void openScanLight() {\n        if (sActivityRef != null && sActivityRef.get() != null) {\n            sActivityRef.get().openLight();\n        }\n    }\n\n    /**\n     * 关闭手电筒\n     */\n    public static void closeScanLight() {\n        if (sActivityRef != null && sActivityRef.get() != null) {\n            sActivityRef.get().closeLight();\n        }\n    }\n\n    /**\n     * 是否开启手电筒\n     */\n    public static boolean isLightOn() {\n        if (sActivityRef != null && sActivityRef.get() != null) {\n            return sActivityRef.get().is_light_on;\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/utils/AmbientLightManager.java",
    "content": "/*\n * Copyright (C) Jenly, MLKit Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.maning.mlkitscanner.scan.utils;\n\nimport android.content.Context;\nimport android.hardware.Sensor;\nimport android.hardware.SensorEvent;\nimport android.hardware.SensorEventListener;\nimport android.hardware.SensorManager;\n\n/**\n * @author <a href=\"mailto:jenly1314@gmail.com\">Jenly</a>\n */\npublic class AmbientLightManager implements SensorEventListener {\n\n    private static final int INTERVAL_TIME = 200;\n\n    protected static final float DARK_LUX = 45.0f;\n    protected static final float BRIGHT_LUX = 100.0f;\n\n    /**\n     * 光线太暗时，默认：照度45 lux\n     */\n    private float darkLightLux = DARK_LUX;\n    /**\n     * 光线足够亮时，默认：照度100 lux\n     */\n    private float brightLightLux = BRIGHT_LUX;\n\n    private SensorManager sensorManager;\n    private Sensor lightSensor;\n\n    private long lastTime;\n\n    private boolean isLightSensorEnabled;\n\n    private OnLightSensorEventListener mOnLightSensorEventListener;\n\n    public AmbientLightManager(Context context) {\n        sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);\n        lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);\n        isLightSensorEnabled = true;\n    }\n\n    public void register() {\n        if (sensorManager != null && lightSensor != null) {\n            sensorManager.registerListener(this, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);\n        }\n    }\n\n    public void unregister() {\n        if (sensorManager != null && lightSensor != null) {\n            sensorManager.unregisterListener(this);\n        }\n    }\n\n\n    @Override\n    public void onSensorChanged(SensorEvent sensorEvent) {\n        if(isLightSensorEnabled){\n            long currentTime = System.currentTimeMillis();\n            if(currentTime - lastTime < INTERVAL_TIME){//降低频率\n                return;\n            }\n            lastTime = currentTime;\n\n            if (mOnLightSensorEventListener != null) {\n                float lightLux = sensorEvent.values[0];\n                mOnLightSensorEventListener.onSensorChanged(lightLux);\n                if (lightLux <= darkLightLux) {\n                    mOnLightSensorEventListener.onSensorChanged(true,lightLux);\n                } else if (lightLux >= brightLightLux) {\n                    mOnLightSensorEventListener.onSensorChanged(false,lightLux);\n                }\n            }\n        }\n    }\n\n    /**\n     * 设置光线足够暗的阈值（单位：lux）\n     * @param lightLux\n     */\n    public void setDarkLightLux(float lightLux){\n        this.darkLightLux = lightLux;\n    }\n\n    /**\n     * 设置光线足够明亮的阈值（单位：lux）\n     * @param lightLux\n     */\n    public void setBrightLightLux(float lightLux){\n        this.brightLightLux = lightLux;\n    }\n\n    @Override\n    public void onAccuracyChanged(Sensor sensor, int accuracy) {\n        // do nothing\n    }\n\n    public boolean isLightSensorEnabled() {\n        return isLightSensorEnabled;\n    }\n\n    /**\n     * 设置是否启用光线亮度传感器\n     * @param lightSensorEnabled\n     */\n    public void setLightSensorEnabled(boolean lightSensorEnabled) {\n        isLightSensorEnabled = lightSensorEnabled;\n    }\n\n    /**\n     * 设置光线亮度传感器监听器，只有在 {@link #isLightSensorEnabled} 为{@code true} 才有效\n     * @param listener\n     */\n    public void setOnLightSensorEventListener(OnLightSensorEventListener listener){\n        mOnLightSensorEventListener = listener;\n    }\n\n    public interface OnLightSensorEventListener{\n        /**\n         *\n         * @param lightLux 当前检测到的光线照度值\n         */\n        default void onSensorChanged(float lightLux){\n\n        }\n\n        /**\n         * 传感器改变事件\n         * @param dark 是否太暗了，当检测到的光线照度值小于{@link #darkLightLux}时，为{@code true}\n         * @param lightLux 当前检测到的光线照度值\n         */\n        void onSensorChanged(boolean dark, float lightLux);\n    }\n}"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/utils/BeepManager.java",
    "content": "/*\n * Copyright (C) Jenly, MLKit Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.maning.mlkitscanner.scan.utils;\n\nimport android.content.Context;\nimport android.content.res.AssetFileDescriptor;\nimport android.media.AudioManager;\nimport android.media.MediaPlayer;\nimport android.os.Vibrator;\n\n\nimport com.maning.mlkitscanner.R;\n\nimport java.io.Closeable;\n\n/**\n * @author <a href=\"mailto:jenly1314@gmail.com\">Jenly</a>\n */\npublic final class BeepManager implements MediaPlayer.OnErrorListener, Closeable {\n\n    private static final long VIBRATE_DURATION = 200L;\n\n    private final Context context;\n    private MediaPlayer mediaPlayer;\n    private Vibrator vibrator;\n    private boolean playBeep;\n    private boolean vibrate;\n\n    public BeepManager(Context context) {\n        this.context = context;\n        this.mediaPlayer = null;\n        updatePrefs();\n    }\n\n    public void setVibrate(boolean vibrate){\n        this.vibrate = vibrate;\n    }\n\n    public void setPlayBeep(boolean playBeep){\n        this.playBeep = playBeep;\n    }\n\n    private synchronized void updatePrefs() {\n        if (mediaPlayer == null) {\n            mediaPlayer = buildMediaPlayer(context);\n        }\n        if(vibrator == null){\n            vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);\n        }\n    }\n\n    public synchronized void playBeepSoundAndVibrate() {\n        if (playBeep && mediaPlayer != null) {\n            mediaPlayer.start();\n        }\n        if (vibrate) {\n            vibrator.vibrate(VIBRATE_DURATION);\n        }\n    }\n\n    private MediaPlayer buildMediaPlayer(Context context) {\n        MediaPlayer mediaPlayer = new MediaPlayer();\n        try {\n            AssetFileDescriptor file = context.getResources().openRawResourceFd(R.raw.mn_scan_beep);\n            mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength());\n            mediaPlayer.setOnErrorListener(this);\n            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);\n            mediaPlayer.setLooping(false);\n            mediaPlayer.prepare();\n            return mediaPlayer;\n        } catch (Exception e) {\n            mediaPlayer.release();\n            return null;\n        }\n    }\n\n    @Override\n    public synchronized boolean onError(MediaPlayer mp, int what, int extra) {\n        close();\n        updatePrefs();\n        return true;\n    }\n\n    @Override\n    public synchronized void close() {\n        try{\n            if (mediaPlayer != null) {\n                mediaPlayer.release();\n                mediaPlayer = null;\n            }\n        }catch (Exception e){\n        }\n    }\n\n}"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/utils/CommonUtils.java",
    "content": "package com.maning.mlkitscanner.scan.utils;\n\nimport android.content.Context;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.util.DisplayMetrics;\nimport android.view.WindowManager;\n\n/**\n * Created by maning on 2017/11/9.\n */\n\npublic class CommonUtils {\n    /**\n     * 根据手机分辨率从DP转成PX\n     *\n     * @param context\n     * @param dpValue\n     * @return\n     */\n    public static int dip2px(Context context, float dpValue) {\n        float scale = context.getResources().getDisplayMetrics().density;\n        return (int) (dpValue * scale + 0.5f);\n    }\n\n    /**\n     * 将sp值转换为px值，保证文字大小不变\n     *\n     * @param spValue\n     * @return\n     */\n    public static int sp2px(Context context, float spValue) {\n        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;\n        return (int) (spValue * fontScale + 0.5f);\n    }\n\n    /**\n     * 根据手机的分辨率PX(像素)转成DP\n     *\n     * @param context\n     * @param pxValue\n     * @return\n     */\n    public static int px2dip(Context context, float pxValue) {\n        float scale = context.getResources().getDisplayMetrics().density;\n        return (int) (pxValue / scale + 0.5f);\n    }\n\n    /**\n     * 将px值转换为sp值，保证文字大小不变\n     *\n     * @param pxValue\n     * @return\n     */\n\n    public static int px2sp(Context context, float pxValue) {\n        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;\n        return (int) (pxValue / fontScale + 0.5f);\n    }\n\n    public static int getScreenWidth(Context context) {\n        try {\n            final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);\n            final DisplayMetrics outMetrics = new DisplayMetrics();\n            wm.getDefaultDisplay().getMetrics(outMetrics);\n            return outMetrics.widthPixels;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        return 0;\n    }\n\n    public static int getTextWidth(String text, Paint paint){\n        Rect rect = new Rect();\n        paint.getTextBounds(text, 0, text.length(), rect);\n        return rect.width();\n    }\n\n    public static int getTextHeight(String text, Paint paint){\n        Rect rect = new Rect();\n        paint.getTextBounds(text, 0, text.length(), rect);\n        return rect.height();\n    }\n\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/utils/ImageUtils.java",
    "content": "/*\n * Copyright (C) Jenly, MLKit Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.maning.mlkitscanner.scan.utils;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.ImageFormat;\nimport android.graphics.Matrix;\nimport android.graphics.Rect;\nimport android.graphics.YuvImage;\nimport android.net.Uri;\nimport android.util.DisplayMetrics;\n\nimport androidx.camera.core.ImageProxy;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\n\n/**\n * @author <a href=\"mailto:jenly1314@gmail.com\">Jenly</a>\n */\npublic class ImageUtils {\n\n    private ImageUtils(){\n        throw new AssertionError();\n    }\n\n    public static Bitmap imageProxyToBitmap(ImageProxy imageProxy) throws Exception {\n        return imageProxyToBitmap(imageProxy,0);\n    }\n\n    public static Bitmap imageProxyToBitmap(ImageProxy imageProxy, int rotationDegrees) throws Exception {\n        ImageProxy.PlaneProxy[] plane = imageProxy.getPlanes();\n        ByteBuffer yBuffer = plane[0].getBuffer();  // Y\n        ByteBuffer uBuffer = plane[1].getBuffer();  // U\n        ByteBuffer vBuffer = plane[2].getBuffer();  // V\n\n        int ySize = yBuffer.remaining();\n        int uSize = uBuffer.remaining();\n        int vSize = vBuffer.remaining();\n\n        byte[] nv21 = new byte[ySize + uSize + vSize];\n\n        //U and V are swapped\n        yBuffer.get(nv21, 0, ySize);\n        vBuffer.get(nv21, ySize, vSize);\n        uBuffer.get(nv21, ySize + vSize, uSize);\n\n        YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, imageProxy.getWidth(), imageProxy.getHeight(), null);\n        ByteArrayOutputStream stream = new ByteArrayOutputStream(nv21.length);\n        yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()), 90, stream);\n\n        Bitmap bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());\n        if(rotationDegrees != 0){\n            Matrix matrix = new Matrix();\n            matrix.postRotate(rotationDegrees);\n            bitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(), matrix, true);\n        }\n\n        return bitmap;\n    }\n\n    public static Bitmap getBitmap(Context context,Uri uri){\n        InputStream Stream = null;\n        InputStream inputStream = null;\n        try {\n            //根据uri获取图片的流\n            inputStream = context.getContentResolver().openInputStream(uri);\n            BitmapFactory.Options options = new BitmapFactory.Options();\n            //options的in系列的设置了，injustdecodebouond只解析图片的大小，而不加载到内存中去\n            options.inJustDecodeBounds = true;\n            //1.如果通过options.outHeight获取图片的宽高，就必须通过decodestream解析同options赋值\n            //否则options.outheight获取不到宽高\n            BitmapFactory.decodeStream(inputStream,null,options);\n            //2.通过 btm.getHeight()获取图片的宽高就不需要1的解析，我这里采取第一张方式\n//            Bitmap btm = BitmapFactory.decodeStream(inputStream);\n            //以屏幕的宽高进行压缩\n            DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();\n            int heightPixels = displayMetrics.heightPixels;\n            int widthPixels = displayMetrics.widthPixels;\n            //获取图片的宽高\n            int outHeight = options.outHeight;\n            int outWidth = options.outWidth;\n            //heightPixels就是要压缩后的图片高度，宽度也一样\n            int a = (int) Math.ceil((outHeight/(float)heightPixels));\n            int b = (int) Math.ceil(outWidth/(float)widthPixels);\n            //比例计算,一般是图片比较大的情况下进行压缩\n            int max = Math.max(a, b);\n            if(max > 1){\n                options.inSampleSize = max;\n            }\n            //解析到内存中去\n            options.inJustDecodeBounds = false;\n//            根据uri重新获取流，inputstream在解析中发生改变了\n            Stream = context.getContentResolver().openInputStream(uri);\n            Bitmap bitmap = BitmapFactory.decodeStream(Stream, null, options);\n            return bitmap;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }finally {\n            try {\n                if(inputStream != null) {\n                    inputStream.close();\n                }\n                if(Stream != null){\n                    Stream.close();\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n\n        }\n        return  null;\n    }\n\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/utils/StatusBarUtil.java",
    "content": "package com.maning.mlkitscanner.scan.utils;\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.Window;\nimport android.view.WindowManager;\n\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.regex.Pattern;\n\n/**\n * @author：created by leaf on 2019-05-07\n * Github地址：https://github.com/Ye-Miao\n * Desc: 状态栏工具类\n */\npublic class StatusBarUtil {\n\n    private static final int DEFAULT_ALPHA = 0;\n\n    /**\n     * 设置状态栏颜色（自定义颜色)\n     *\n     * @param activity 目标activity\n     * @param color    状态栏颜色值\n     */\n    public static void setColor(Activity activity, int color) {\n        WeakReference<Activity> activityWeakReference = new WeakReference<>(activity);\n        setColor(activityWeakReference.get(), color, DEFAULT_ALPHA);\n    }\n\n    /**\n     * 设置纯色状态栏（自定义颜色，alpha）\n     *\n     * @param activity 目标activity\n     * @param color    状态栏颜色值\n     * @param alpha    状态栏透明度\n     */\n    public static void setColor(Activity activity, int color, int alpha) {\n        WeakReference<Activity> activityWeakReference = new WeakReference<>(activity);\n        Window window = activityWeakReference.get().getWindow();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);\n            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);\n            window.setStatusBarColor(cipherColor(color, alpha));\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);\n            setTranslucentView((ViewGroup) window.getDecorView(), color, alpha);\n            setRootView(activityWeakReference.get(), true);\n        }\n    }\n\n    /**\n     * 设置状态栏渐变颜色\n     *\n     * @param activity 目标activity\n     * @param view     目标View\n     */\n    public static void setGradientColor(Activity activity, View view) {\n        WeakReference<Activity> activityWeakReference = new WeakReference<>(activity);\n        ViewGroup decorView = (ViewGroup) activityWeakReference.get().getWindow().getDecorView();\n        View fakeStatusBarView = decorView.findViewById(android.R.id.custom);\n        if (fakeStatusBarView != null) {\n            decorView.removeView(fakeStatusBarView);\n        }\n        setRootView(activityWeakReference.get(), false);\n        setTransparentForWindow(activityWeakReference.get());\n        setPaddingTop(activityWeakReference.get(), view);\n    }\n\n    /**\n     * 设置透明状态栏\n     *\n     * @param activity 目标界面\n     */\n    public static void setTransparentForWindow(Activity activity) {\n        WeakReference<Activity> activityWeakReference = new WeakReference<>(activity);\n        Window window = activityWeakReference.get().getWindow();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);\n            window.setStatusBarColor(Color.TRANSPARENT);\n            window.getDecorView()\n                    .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);\n        }\n    }\n\n    /**\n     * 增加View的paddingTop,增加的值为状态栏高度 (智能判断，并设置高度)\n     *\n     * @param context 目标Context\n     * @param view    需要增高的View\n     */\n    public static void setPaddingTop(Context context, View view) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            ViewGroup.LayoutParams lp = view.getLayoutParams();\n            if (lp != null && lp.height > 0 && view.getPaddingTop() == 0) {\n                lp.height += getStatusBarHeight(context);\n                view.setPadding(view.getPaddingLeft(), view.getPaddingTop() + getStatusBarHeight(context),\n                        view.getPaddingRight(), view.getPaddingBottom());\n            }\n        }\n    }\n\n\n    /**\n     * 设置状态栏darkMode,字体颜色及icon变黑(目前支持MIUI6以上,Flyme4以上,Android M以上)\n     *\n     * @param activity 目标activity\n     */\n    public static void setDarkMode(Activity activity) {\n        WeakReference<Activity> activityWeakReference = new WeakReference<>(activity);\n        darkMode(activityWeakReference.get().getWindow(), true);\n    }\n\n    /**\n     * 设置状态栏darkMode,字体颜色及icon变亮(目前支持MIUI6以上,Flyme4以上,Android M以上)\n     *\n     * @param activity 目标activity\n     */\n    public static void setLightMode(Activity activity) {\n        WeakReference<Activity> activityWeakReference = new WeakReference<>(activity);\n        darkMode(activityWeakReference.get().getWindow(), false);\n    }\n\n    @TargetApi(Build.VERSION_CODES.M)\n    private static void darkMode(Window window, boolean dark) {\n        if (isFlyme4()) {\n            setModeForFlyme4(window, dark);\n        } else if (isMIUI6()) {\n            setModeForMIUI6(window, dark);\n        }\n        darkModeForM(window, dark);\n    }\n\n\n    /**\n     * android 6.0设置字体颜色\n     *\n     * @param window 目标window\n     * @param dark   亮色 or 暗色\n     */\n    private static void darkModeForM(Window window, boolean dark) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            int systemUiVisibility = window.getDecorView().getSystemUiVisibility();\n            if (dark) {\n                systemUiVisibility |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;\n            } else {\n                systemUiVisibility &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;\n            }\n            window.getDecorView().setSystemUiVisibility(systemUiVisibility);\n        }\n    }\n\n\n    /**\n     * 设置MIUI6+的状态栏的darkMode,darkMode时候字体颜色及icon\n     * http://dev.xiaomi.com/doc/p=4769/\n     *\n     * @param window 目标window\n     * @param dark   亮色 or 暗色\n     */\n    private static void setModeForMIUI6(Window window, boolean dark) {\n        Class<? extends Window> clazz = window.getClass();\n        try {\n            Class<?> layoutParams = Class.forName(\"android.view.MiuiWindowManager$LayoutParams\");\n            Field field = layoutParams.getField(\"EXTRA_FLAG_STATUS_BAR_DARK_MODE\");\n            int darkModeFlag = field.getInt(layoutParams);\n            Method extraFlagField = clazz.getMethod(\"setExtraFlags\", int.class, int.class);\n            extraFlagField.invoke(window, dark ? darkModeFlag : 0, darkModeFlag);\n        } catch (Exception e) {\n            Log.e(\"StatusBar\", \"darkIcon: failed\");\n        }\n\n    }\n\n    /**\n     * 设置Flyme4+的状态栏的darkMode,darkMode时候字体颜色及icon\n     * http://open-wiki.flyme.cn/index.php?title=Flyme%E7%B3%BB%E7%BB%9FAPI\n     *\n     * @param window 目标window\n     * @param dark   亮色 or 暗色\n     */\n    private static void setModeForFlyme4(Window window, boolean dark) {\n        try {\n            WindowManager.LayoutParams lp = window.getAttributes();\n            Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField(\"MEIZU_FLAG_DARK_STATUS_BAR_ICON\");\n            Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField(\"meizuFlags\");\n            darkFlag.setAccessible(true);\n            meizuFlags.setAccessible(true);\n            int bit = darkFlag.getInt(null);\n            int value = meizuFlags.getInt(lp);\n            if (dark) {\n                value |= bit;\n            } else {\n                value &= ~bit;\n            }\n            meizuFlags.setInt(lp, value);\n            window.setAttributes(lp);\n        } catch (Exception e) {\n            Log.e(\"StatusBar\", \"darkIcon: failed\");\n        }\n    }\n\n\n    /**\n     * 判断是否Flyme4以上\n     */\n    private static boolean isFlyme4() {\n        return Build.FINGERPRINT.contains(\"Flyme_OS_4\") || Build.VERSION.INCREMENTAL.contains(\"Flyme_OS_4\")\n                || Pattern.compile(\"Flyme OS [4|5]\", Pattern.CASE_INSENSITIVE).matcher(Build.DISPLAY).find();\n    }\n\n    /**\n     * 判断是否MIUI6以上\n     */\n    private static boolean isMIUI6() {\n        try {\n            Class<?> clz = Class.forName(\"android.os.SystemProperties\");\n            Method mtd = clz.getMethod(\"get\", String.class);\n            String val = (String) mtd.invoke(null, \"ro.miui.ui.version.name\");\n            val = val.replaceAll(\"[vV]\", \"\");\n            int version = Integer.parseInt(val);\n            return version >= 6;\n        } catch (Exception e) {\n            return false;\n        }\n    }\n\n    /**\n     * 计算alpha色值\n     *\n     * @param color 状态栏颜色值\n     * @param alpha 状态栏透明度\n     */\n    private static int cipherColor(int color, int alpha) {\n        if (alpha == 0) {\n            return color;\n        }\n        float a = 1 - alpha / 255f;\n        int red = color >> 16 & 0xff;\n        int green = color >> 8 & 0xff;\n        int blue = color & 0xff;\n        red = (int) (red * a + 0.5);\n        green = (int) (green * a + 0.5);\n        blue = (int) (blue * a + 0.5);\n        return 0xff << 24 | red << 16 | green << 8 | blue;\n    }\n\n\n    /**\n     * 创建透明View\n     *\n     * @param viewGroup 目标视图\n     * @param color     状态栏颜色值\n     * @param alpha     状态栏透明度\n     */\n    private static void setTranslucentView(ViewGroup viewGroup, int color, int alpha) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            int cipherColor = cipherColor(color, alpha);\n            View translucentView = viewGroup.findViewById(android.R.id.custom);\n            if (translucentView == null && cipherColor != 0) {\n                translucentView = new View(viewGroup.getContext());\n                translucentView.setId(android.R.id.custom);\n                ViewGroup.LayoutParams params =\n                        new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(viewGroup.getContext()));\n                viewGroup.addView(translucentView, params);\n            }\n            if (translucentView != null) {\n                translucentView.setBackgroundColor(cipherColor);\n            }\n        }\n\n    }\n\n    /**\n     * 设置根布局参数\n     *\n     * @param activity         目标activity\n     * @param fitSystemWindows 是否预留toolbar的高度\n     */\n    private static void setRootView(Activity activity, boolean fitSystemWindows) {\n        WeakReference<Activity> activityWeakReference = new WeakReference<>(activity);\n        ViewGroup parent = activityWeakReference.get().findViewById(android.R.id.content);\n        for (int i = 0, count = parent.getChildCount(); i < count; i++) {\n            View childView = parent.getChildAt(i);\n            if (childView instanceof ViewGroup) {\n                childView.setFitsSystemWindows(fitSystemWindows);\n                ((ViewGroup) childView).setClipToPadding(fitSystemWindows);\n            }\n        }\n    }\n\n    /**\n     * 获取状态栏高度\n     *\n     * @param context 目标Context\n     */\n    public static int getStatusBarHeight(Context context) {\n        // 获得状态栏高度\n        int resourceId = context.getResources().getIdentifier(\"status_bar_height\", \"dimen\", \"android\");\n        return context.getResources().getDimensionPixelSize(resourceId);\n    }\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/utils/ZXingUtils.java",
    "content": "package com.maning.mlkitscanner.scan.utils;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Color;\nimport android.graphics.Matrix;\nimport android.text.TextUtils;\n\nimport com.google.zxing.BarcodeFormat;\nimport com.google.zxing.BinaryBitmap;\nimport com.google.zxing.DecodeHintType;\nimport com.google.zxing.EncodeHintType;\nimport com.google.zxing.MultiFormatReader;\nimport com.google.zxing.Result;\nimport com.google.zxing.WriterException;\nimport com.google.zxing.common.BitMatrix;\nimport com.google.zxing.common.HybridBinarizer;\nimport com.google.zxing.qrcode.QRCodeWriter;\nimport com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;\n\nimport java.io.UnsupportedEncodingException;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.EnumMap;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Created by maning on 2017/11/10.\n */\n\npublic class ZXingUtils {\n\n    public static final Map<DecodeHintType, Object> HINTS = new EnumMap<>(DecodeHintType.class);\n\n    static {\n        List<BarcodeFormat> allFormats = new ArrayList<>();\n        allFormats.add(BarcodeFormat.AZTEC);\n        allFormats.add(BarcodeFormat.CODABAR);\n        allFormats.add(BarcodeFormat.CODE_39);\n        allFormats.add(BarcodeFormat.CODE_93);\n        allFormats.add(BarcodeFormat.CODE_128);\n        allFormats.add(BarcodeFormat.DATA_MATRIX);\n        allFormats.add(BarcodeFormat.EAN_8);\n        allFormats.add(BarcodeFormat.EAN_13);\n        allFormats.add(BarcodeFormat.ITF);\n        allFormats.add(BarcodeFormat.MAXICODE);\n        allFormats.add(BarcodeFormat.PDF_417);\n        allFormats.add(BarcodeFormat.QR_CODE);\n        allFormats.add(BarcodeFormat.RSS_14);\n        allFormats.add(BarcodeFormat.RSS_EXPANDED);\n        allFormats.add(BarcodeFormat.UPC_A);\n        allFormats.add(BarcodeFormat.UPC_E);\n        allFormats.add(BarcodeFormat.UPC_EAN_EXTENSION);\n\n        HINTS.put(DecodeHintType.POSSIBLE_FORMATS, allFormats);\n        HINTS.put(DecodeHintType.CHARACTER_SET, \"utf-8\");\n    }\n\n    public static Bitmap createQRCodeImage(String content) {\n        return createQRCodeImage(content, 500, 0, Color.BLACK, Color.WHITE, null, null, null);\n    }\n\n    public static Bitmap createQRCodeImage(String content, int size) {\n        return createQRCodeImage(content, size, 0, Color.BLACK, Color.WHITE, null, null, null);\n    }\n\n    public static Bitmap createQRCodeImage(String content, int size, int margin) {\n        return createQRCodeImage(content, size, margin, Color.BLACK, Color.WHITE, null, null, null);\n    }\n\n    public static Bitmap createQRCodeImage(String text, Bitmap logo_bitmap) {\n        return createQRCodeImage(text, 500, 0, Color.BLACK, Color.WHITE, null, logo_bitmap, null);\n    }\n\n    public static Bitmap createQRCodeImage(String text, int size, Bitmap logo_bitmap) {\n        return createQRCodeImage(text, size, 0, Color.BLACK, Color.WHITE, null, logo_bitmap, null);\n    }\n\n\n    public static Bitmap createQRCodeImage(String text, int size, int margin, Bitmap logo_bitmap) {\n        return createQRCodeImage(text, size, margin, Color.BLACK, Color.WHITE, null, logo_bitmap, null);\n    }\n\n    /**\n     * 生成带logo的二维码，logo默认为二维码的1/5\n     *\n     * @param text                   需要生成二维码的内容\n     * @param size                   需要生成二维码的大小\n     * @param margin                 二维码边距\n     * @param foreground_color       二维码前景色\n     * @param background_color       二维码背景颜色\n     * @param error_correction_level 容错率 L：7% M：15% Q：25% H：35%\n     * @param logo_bitmap            logo文件\n     * @return bitmap\n     */\n    public static Bitmap createQRCodeImage(String text, int size, int margin, int foreground_color, int background_color, String error_correction_level, Bitmap logo_bitmap) {\n        return createQRCodeImage(text, size, margin, foreground_color, background_color, error_correction_level, logo_bitmap, null);\n    }\n\n    /**\n     * 生成带logo的二维码，logo默认为二维码的1/5\n     *\n     * @param text                   需要生成二维码的内容\n     * @param size                   需要生成二维码的大小\n     * @param margin                 二维码边距\n     * @param foreground_color       二维码前景色\n     * @param background_color       二维码背景颜色\n     * @param error_correction_level 容错率 L：7% M：15% Q：25% H：35%\n     * @param logo_bitmap            logo文件\n     * @param logo_bitmap            二维码前景图片，不建议使用（可能太花识别率会降低）\n     * @return bitmap\n     */\n    public static Bitmap createQRCodeImage(String text, int size, int margin, int foreground_color, int background_color, String error_correction_level, Bitmap logo_bitmap, Bitmap foreground_bitmap) {\n        try {\n            int IMAGE_HALFWIDTH = size / 10;\n            Hashtable<EncodeHintType, Object> hints = new Hashtable<>();\n            hints.put(EncodeHintType.CHARACTER_SET, \"UTF-8\");\n            hints.put(EncodeHintType.MARGIN, Math.max(margin, 0));\n            /*\n             * 设置容错级别，默认为ErrorCorrectionLevel.L\n             * 因为中间加入logo所以建议你把容错级别调至H,否则可能会出现识别不了\n             */\n            if (TextUtils.isEmpty(error_correction_level)) {\n                if (logo_bitmap != null) {\n                    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);\n                } else {\n                    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);\n                }\n            } else {\n                hints.put(EncodeHintType.ERROR_CORRECTION, error_correction_level);\n            }\n\n\n            BitMatrix bitMatrix = new QRCodeWriter().encode(text,\n                    BarcodeFormat.QR_CODE, size, size, hints);\n\n            int width = bitMatrix.getWidth();\n            int height = bitMatrix.getHeight();\n            int halfW = width / 2;\n            int halfH = height / 2;\n\n            if (logo_bitmap != null) {\n                Matrix m = new Matrix();\n                float sx = (float) 2 * IMAGE_HALFWIDTH / logo_bitmap.getWidth();\n                float sy = (float) 2 * IMAGE_HALFWIDTH / logo_bitmap.getHeight();\n                m.setScale(sx, sy);\n                //设置缩放信息\n                //将logo图片按martix设置的信息缩放\n                logo_bitmap = Bitmap.createBitmap(logo_bitmap, 0, 0,\n                        logo_bitmap.getWidth(), logo_bitmap.getHeight(), m, false);\n            }\n            if (foreground_bitmap != null) {\n                //从当前位图按一定的比例创建一个新的位图\n                foreground_bitmap = Bitmap.createScaledBitmap(foreground_bitmap, width, height, false);\n            }\n\n            int[] pixels = new int[size * size];\n            for (int y = 0; y < size; y++) {\n                for (int x = 0; x < size; x++) {\n                    if (logo_bitmap != null) {\n                        if (x > halfW - IMAGE_HALFWIDTH && x < halfW + IMAGE_HALFWIDTH\n                                && y > halfH - IMAGE_HALFWIDTH\n                                && y < halfH + IMAGE_HALFWIDTH) {\n                            //该位置用于存放图片信息\n                            //记录图片每个像素信息\n                            pixels[y * width + x] = logo_bitmap.getPixel(x - halfW\n                                    + IMAGE_HALFWIDTH, y - halfH + IMAGE_HALFWIDTH);\n                        } else {\n                            if (bitMatrix.get(x, y)) {\n                                if (foreground_bitmap != null) {\n                                    pixels[y * width + x] = foreground_bitmap.getPixel(x, y);\n                                } else {\n                                    pixels[y * width + x] = foreground_color;\n                                }\n                            } else {\n                                pixels[y * size + x] = background_color;\n                            }\n                        }\n                    } else {\n                        if (bitMatrix.get(x, y)) {\n                            if (foreground_bitmap != null) {\n                                pixels[y * width + x] = foreground_bitmap.getPixel(x, y);\n                            } else {\n                                pixels[y * width + x] = foreground_color;\n                            }\n                        } else {\n                            pixels[y * size + x] = background_color;\n                        }\n                    }\n\n                }\n            }\n            Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);\n            bitmap.setPixels(pixels, 0, size, 0, 0, size, size);\n            return bitmap;\n        } catch (WriterException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n\n    //------解析图片-----\n\n    /**\n     * 同步解析本地图片二维码。该方法是耗时操作，请在子线程中调用。\n     *\n     * @param picturePath 要解析的二维码图片本地路径\n     * @return 返回二维码图片里的内容 或 null\n     */\n    public static String syncDecodeQRCode(String picturePath) {\n        return syncDecodeQRCode(getDecodeAbleBitmap(picturePath));\n    }\n\n    /**\n     * 同步解析bitmap二维码。该方法是耗时操作，请在子线程中调用。\n     *\n     * @param bitmap 要解析的二维码图片\n     * @return 返回二维码图片里的内容 或 null\n     */\n    public static String syncDecodeQRCode(Bitmap bitmap) {\n        try {\n            int width = bitmap.getWidth();\n            int height = bitmap.getHeight();\n            int[] pixels = new int[width * height];\n            bitmap.getPixels(pixels, 0, width, 0, 0, width, height);\n            com.google.zxing.RGBLuminanceSource source = new com.google.zxing.RGBLuminanceSource(width, height, pixels);\n            Result result = new MultiFormatReader().decode(new BinaryBitmap(new HybridBinarizer(source)), HINTS);\n            if (result != null) {\n                return recode(result.getText());\n            } else {\n                return null;\n            }\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    /**\n     * 将本地图片文件转换成可解码二维码的 Bitmap\n     *\n     * @param picturePath 本地图片文件路径\n     * @return\n     */\n    private static Bitmap getDecodeAbleBitmap(String picturePath) {\n        try {\n            BitmapFactory.Options options = new BitmapFactory.Options();\n            options.inJustDecodeBounds = true;\n            BitmapFactory.decodeFile(picturePath, options);\n            int sampleSize = options.outHeight / 400;\n            if (sampleSize <= 0) {\n                sampleSize = 1;\n            }\n            options.inSampleSize = sampleSize;\n            options.inJustDecodeBounds = false;\n\n            return BitmapFactory.decodeFile(picturePath, options);\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    /**\n     * 中文乱码\n     *\n     * @return\n     */\n    public static String recode(String str) {\n        String formart = \"\";\n        try {\n            boolean ISO = Charset.forName(\"ISO-8859-1\").newEncoder()\n                    .canEncode(str);\n            if (ISO) {\n                formart = new String(str.getBytes(\"ISO-8859-1\"), \"GB2312\");\n            } else {\n                formart = str;\n            }\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n        return formart;\n    }\n\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/view/ScanActionMenuView.java",
    "content": "package com.maning.mlkitscanner.scan.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.RelativeLayout;\nimport android.widget.TextView;\n\nimport com.maning.mlkitscanner.R;\nimport com.maning.mlkitscanner.scan.callback.MNCustomViewBindCallback;\nimport com.maning.mlkitscanner.scan.model.MNScanConfig;\n\n\n/**\n * @author : maning\n * @date : 2020-09-04\n * @desc :\n */\npublic class ScanActionMenuView extends FrameLayout {\n\n    private LinearLayout btn_scan_light;\n    private ImageView iv_scan_light;\n    private TextView tv_scan_light;\n    private LinearLayout btn_close;\n    private LinearLayout btn_photo;\n\n    private RelativeLayout rl_default_menu;\n    private LinearLayout ll_custom_view;\n\n    private OnScanActionMenuListener onScanActionMenuListener;\n\n    public interface OnScanActionMenuListener {\n        void onClose();\n\n        void onLight();\n\n        void onPhoto();\n    }\n\n    public void setOnScanActionMenuListener(OnScanActionMenuListener onScanActionMenuListener) {\n        this.onScanActionMenuListener = onScanActionMenuListener;\n    }\n\n\n    public ScanActionMenuView(Context context) {\n        this(context, null);\n    }\n\n    public ScanActionMenuView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public ScanActionMenuView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initView();\n    }\n\n    private void initView() {\n        //绑定\n        LayoutInflater.from(getContext()).inflate(R.layout.mn_scan_action_menu, this);\n\n        btn_scan_light = (LinearLayout) findViewById(R.id.btn_scan_light);\n        iv_scan_light = (ImageView) findViewById(R.id.iv_scan_light);\n        tv_scan_light = (TextView) findViewById(R.id.tv_scan_light);\n        btn_close = (LinearLayout) findViewById(R.id.btn_close);\n        btn_photo = (LinearLayout) findViewById(R.id.btn_photo);\n        rl_default_menu = (RelativeLayout) findViewById(R.id.rl_default_menu);\n        ll_custom_view = (LinearLayout) findViewById(R.id.ll_custom_view);\n\n        rl_default_menu.setVisibility(View.GONE);\n        ll_custom_view.setVisibility(View.GONE);\n\n        //点击事件\n        btn_scan_light.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if (onScanActionMenuListener != null) {\n                    onScanActionMenuListener.onLight();\n                }\n            }\n        });\n\n        btn_close.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if (onScanActionMenuListener != null) {\n                    onScanActionMenuListener.onClose();\n                }\n            }\n        });\n        btn_photo.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if (onScanActionMenuListener != null) {\n                    onScanActionMenuListener.onPhoto();\n                }\n            }\n        });\n\n    }\n\n    private MNScanConfig scanConfig;\n\n    public void setScanConfig(MNScanConfig config, MNCustomViewBindCallback customViewBindCallback) {\n        this.scanConfig = config;\n\n        //自定义View\n        int customShadeViewLayoutID = scanConfig.getCustomShadeViewLayoutID();\n        if (customShadeViewLayoutID > 0 && customViewBindCallback != null) {\n            //显示出来\n            ll_custom_view.setVisibility(View.VISIBLE);\n            View customView = LayoutInflater.from(getContext()).inflate(customShadeViewLayoutID, null);\n            ll_custom_view.addView(customView);\n            //事件绑定\n            customViewBindCallback.onBindView(customView);\n        } else {\n            rl_default_menu.setVisibility(View.VISIBLE);\n        }\n\n        //闪光灯配置\n        boolean showLightController = scanConfig.isShowLightController();\n        if (showLightController) {\n            btn_scan_light.setVisibility(View.VISIBLE);\n        } else {\n            btn_scan_light.setVisibility(View.GONE);\n        }\n        //其他配置\n        if (!scanConfig.isShowPhotoAlbum()) {\n            btn_photo.setVisibility(View.GONE);\n        }\n    }\n\n    public void openLight() {\n        iv_scan_light.setImageResource(R.drawable.mn_icon_scan_flash_light_on);\n        tv_scan_light.setText(\"关闭手电筒\");\n    }\n\n    public void closeLight() {\n        iv_scan_light.setImageResource(R.drawable.mn_icon_scan_flash_light_off);\n        tv_scan_light.setText(\"打开手电筒\");\n    }\n\n\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/view/ScanResultPointView.java",
    "content": "package com.maning.mlkitscanner.scan.view;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Color;\nimport android.graphics.Rect;\nimport android.graphics.drawable.GradientDrawable;\nimport android.os.Build;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.RelativeLayout;\nimport android.widget.TextView;\n\nimport com.google.mlkit.vision.barcode.common.Barcode;\nimport com.maning.mlkitscanner.R;\nimport com.maning.mlkitscanner.scan.model.MNScanConfig;\nimport com.maning.mlkitscanner.scan.utils.CommonUtils;\nimport com.maning.mlkitscanner.scan.utils.StatusBarUtil;\n\nimport java.util.List;\n\nimport static android.graphics.drawable.GradientDrawable.RECTANGLE;\n\n/**\n * @author : maning\n * @date : 2021/1/7\n * @desc : 扫描结果点View展示\n */\npublic class ScanResultPointView extends FrameLayout {\n\n    private MNScanConfig scanConfig;\n    private List<Barcode> resultPoint;\n    private OnResultPointClickListener onResultPointClickListener;\n\n    private int resultPointColor;\n    private int resultPointStrokeColor;\n    private int resultPointWithdHeight;\n    private int resultPointRadiusCorners;\n    private int resultPointStrokeWidth;\n    private TextView tv_cancle;\n    private FrameLayout fl_result_point_root;\n    private View fakeStatusBar;\n    private int statusBarHeight;\n    private ImageView iv_show_result;\n    private Bitmap barcodeBitmap;\n\n    public void setOnResultPointClickListener(OnResultPointClickListener onResultPointClickListener) {\n        this.onResultPointClickListener = onResultPointClickListener;\n    }\n\n    public interface OnResultPointClickListener {\n        void onPointClick(String result);\n\n        void onCancle();\n    }\n\n    public ScanResultPointView(Context context) {\n        this(context, null);\n    }\n\n    public ScanResultPointView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public ScanResultPointView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initView();\n    }\n\n    private void initView() {\n        View view = LayoutInflater.from(getContext()).inflate(R.layout.mn_scan_result_point_view, this);\n        fakeStatusBar = view.findViewById(R.id.fakeStatusBar2);\n        iv_show_result = view.findViewById(R.id.iv_show_result);\n        tv_cancle = view.findViewById(R.id.tv_cancle);\n        fl_result_point_root = view.findViewById(R.id.fl_result_point_root);\n\n        statusBarHeight = StatusBarUtil.getStatusBarHeight(getContext());\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            ViewGroup.LayoutParams fakeStatusBarLayoutParams = fakeStatusBar.getLayoutParams();\n            fakeStatusBarLayoutParams.height = statusBarHeight;\n            fakeStatusBar.setLayoutParams(fakeStatusBarLayoutParams);\n        }\n\n        tv_cancle.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                //隐藏View\n                if (onResultPointClickListener != null) {\n                    onResultPointClickListener.onCancle();\n                }\n                removeAllPoints();\n            }\n        });\n        iv_show_result.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                //拦截点击事件\n            }\n        });\n    }\n\n    public void setScanConfig(MNScanConfig config) {\n        scanConfig = config;\n        initResultPointConfigs();\n    }\n\n    private void initResultPointConfigs() {\n        if (scanConfig == null) {\n            return;\n        }\n        resultPointRadiusCorners = CommonUtils.dip2px(getContext(), scanConfig.getResultPointCorners());\n        resultPointWithdHeight = CommonUtils.dip2px(getContext(), scanConfig.getResultPointWithdHeight());\n        resultPointStrokeWidth = CommonUtils.dip2px(getContext(), scanConfig.getResultPointStrokeWidth());\n        String resultPointColorStr = scanConfig.getResultPointColor();\n        String resultPointStrokeColorStr = scanConfig.getResultPointStrokeColor();\n        if (resultPointWithdHeight == 0) {\n            resultPointWithdHeight = CommonUtils.dip2px(getContext(), 36);\n        }\n        if (resultPointRadiusCorners == 0) {\n            resultPointRadiusCorners = CommonUtils.dip2px(getContext(), 36);\n        }\n        if (resultPointStrokeWidth == 0) {\n            resultPointStrokeWidth = CommonUtils.dip2px(getContext(), 3);\n        }\n        if (!TextUtils.isEmpty(resultPointColorStr)) {\n            resultPointColor = Color.parseColor(resultPointColorStr);\n        } else {\n            resultPointColor = getContext().getResources().getColor(R.color.mn_scan_viewfinder_laser_result_point);\n        }\n        if (!TextUtils.isEmpty(resultPointStrokeColorStr)) {\n            resultPointStrokeColor = Color.parseColor(resultPointStrokeColorStr);\n        } else {\n            resultPointStrokeColor = getContext().getResources().getColor(R.color.mn_scan_viewfinder_laser_result_point_border);\n        }\n    }\n\n    public void setDatas(List<Barcode> results, Bitmap barcode) {\n        this.resultPoint = results;\n        this.barcodeBitmap = barcode;\n        drawableResultPoint();\n    }\n\n    public void removeAllPoints() {\n        fl_result_point_root.removeAllViews();\n    }\n\n    private void drawableResultPoint() {\n        Log.e(\">>>>>>\", \"drawableResultPoint---start\");\n        iv_show_result.setImageBitmap(barcodeBitmap);\n        removeAllPoints();\n        if (resultPoint == null || resultPoint.size() == 0) {\n            if (onResultPointClickListener != null) {\n                onResultPointClickListener.onCancle();\n            }\n            return;\n        }\n        if (scanConfig == null) {\n            scanConfig = new MNScanConfig.Builder().builder();\n        }\n        if (resultPoint.size() == 1) {\n            tv_cancle.setVisibility(View.INVISIBLE);\n        } else {\n            tv_cancle.setVisibility(View.VISIBLE);\n        }\n\n        for (int j = 0; j < resultPoint.size(); j++) {\n            Barcode barcode = resultPoint.get(j);\n            Rect boundingBox = barcode.getBoundingBox();\n            int centerX = boundingBox.centerX();\n            int centerY = boundingBox.centerY();\n\n            View inflate = LayoutInflater.from(getContext()).inflate(R.layout.mn_scan_result_point_item_view, null);\n            RelativeLayout rl_root = inflate.findViewById(R.id.rl_root);\n            ImageView iv_point_bg = inflate.findViewById(R.id.iv_point_bg);\n            ImageView iv_point_arrow = inflate.findViewById(R.id.iv_point_arrow);\n\n            //位置\n            RelativeLayout.LayoutParams lpRoot = new RelativeLayout.LayoutParams(resultPointWithdHeight, resultPointWithdHeight);\n            rl_root.setLayoutParams(lpRoot);\n\n            rl_root.setX(centerX - resultPointWithdHeight / 2.0f);\n            rl_root.setY(centerY - resultPointWithdHeight / 2.0f);\n\n            GradientDrawable gradientDrawable = new GradientDrawable();\n            gradientDrawable.setCornerRadius(resultPointRadiusCorners);\n            gradientDrawable.setShape(RECTANGLE);\n            gradientDrawable.setStroke(resultPointStrokeWidth, resultPointStrokeColor);\n            gradientDrawable.setColor(resultPointColor);\n\n            iv_point_bg.setImageDrawable(gradientDrawable);\n\n            //点的大小\n            ViewGroup.LayoutParams lpPoint = iv_point_bg.getLayoutParams();\n            lpPoint.width = resultPointWithdHeight;\n            lpPoint.height = resultPointWithdHeight;\n            iv_point_bg.setLayoutParams(lpPoint);\n\n            //箭头大小\n            if (resultPoint.size() > 1) {\n                ViewGroup.LayoutParams lpArrow = iv_point_arrow.getLayoutParams();\n                lpArrow.width = resultPointWithdHeight / 2;\n                lpArrow.height = resultPointWithdHeight / 2;\n                iv_point_arrow.setLayoutParams(lpArrow);\n                iv_point_arrow.setVisibility(View.VISIBLE);\n            } else {\n                //一个不需要箭头\n                iv_point_arrow.setVisibility(View.GONE);\n            }\n\n            iv_point_bg.setOnClickListener(new OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    if (onResultPointClickListener != null) {\n                        onResultPointClickListener.onPointClick(barcode.getDisplayValue());\n                    }\n                }\n            });\n\n            fl_result_point_root.addView(inflate);\n        }\n        int childCount = fl_result_point_root.getChildCount();\n        Log.e(\">>>>>>\", \"fl_result_point_root---childCount：\" + childCount);\n        if (childCount <= 0) {\n            //关闭页面\n            if (onResultPointClickListener != null) {\n                onResultPointClickListener.onCancle();\n            }\n        }\n        Log.e(\">>>>>>\", \"drawableResultPoint---end\");\n    }\n\n}"
  },
  {
    "path": "mlkit-scanner/src/main/java/com/maning/mlkitscanner/scan/view/ViewfinderView.java",
    "content": "/*\n * Copyright (C) 2008 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.maning.mlkitscanner.scan.view;\n\nimport android.animation.ValueAnimator;\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.LinearGradient;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.graphics.Shader;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport com.maning.mlkitscanner.R;\nimport com.maning.mlkitscanner.scan.model.MNScanConfig;\nimport com.maning.mlkitscanner.scan.utils.CommonUtils;\n\n\n/**\n * This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial\n * transparency outside it, as well as the laser scanner animation and result points.\n *\n * @author dswitkin@google.com (Daniel Switkin)\n */\npublic final class ViewfinderView extends View {\n\n    private static final String TAG = \"ViewfinderView\";\n    private final Paint paint;\n    private Paint paintResultPoint;\n    private Paint paintText;\n    private Paint paintTextBg;\n    private Paint paintLine;\n    private Paint paintLaser;\n    private int maskColor;\n    private int laserColor;\n\n    private Rect frame;\n    private String hintMsg;\n    private String hintTextColor = \"#FFFFFF\";\n    private int hintTextSize = 13;\n    private int linePosition = 0;\n    private int margin;\n    private int laserLineW;\n    private int cornerLineH;\n    private int cornerLineW;\n    private int gridColumn;\n    private int gridHeight;\n\n    //扫描线风格：0线，1网格\n    private MNScanConfig.LaserStyle laserStyle = MNScanConfig.LaserStyle.Line;\n\n    private MNScanConfig mnScanConfig;\n\n    private ValueAnimator anim;\n    private boolean needAnimation = true;\n\n    public ViewfinderView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n\n        // Initialize these once for performance rather than calling them every time in onDraw().\n        paint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        paintResultPoint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        paintText = new Paint(Paint.ANTI_ALIAS_FLAG);\n        paintTextBg = new Paint(Paint.ANTI_ALIAS_FLAG);\n        paintLine = new Paint(Paint.ANTI_ALIAS_FLAG);\n        paintLaser = new Paint(Paint.ANTI_ALIAS_FLAG);\n        Resources resources = getResources();\n        maskColor = resources.getColor(R.color.mn_scan_viewfinder_mask);\n        laserColor = resources.getColor(R.color.mn_scan_viewfinder_laser);\n        hintMsg = \"扫二维码/条形码\";\n        //文字\n        paintText.setColor(Color.WHITE);\n        paintText.setTextSize(CommonUtils.sp2px(getContext(), hintTextSize));\n        paintText.setTextAlign(Paint.Align.CENTER);\n        paintTextBg.setColor(laserColor);\n        paintTextBg.setTextAlign(Paint.Align.CENTER);\n        //四角\n        paintLine.setColor(laserColor);\n        //扫描线\n        paintLaser.setColor(laserColor);\n        paintResultPoint.setColor(laserColor);\n        //初始化数据大小\n        initSize();\n    }\n\n    private void initSize() {\n        //间距\n        margin = CommonUtils.dip2px(getContext(), 4);\n        //扫描线的宽度\n        laserLineW = CommonUtils.dip2px(getContext(), 4);\n        //四角线块\n        cornerLineH = CommonUtils.dip2px(getContext(), 2);\n        cornerLineW = CommonUtils.dip2px(getContext(), 14);\n        //网格扫描线先关配置\n        gridColumn = 24;\n        gridHeight = CommonUtils.getScreenWidth(getContext()) * 7 / 10;\n    }\n\n    /**\n     * 设置颜色\n     *\n     * @param laserColor\n     */\n    public void setLaserColor(int laserColor) {\n        this.laserColor = laserColor;\n        paintLine.setColor(this.laserColor);\n        paintLaser.setColor(this.laserColor);\n    }\n\n    /**\n     * 扫描线的样式\n     *\n     * @param laserStyle\n     */\n    public void setLaserStyle(MNScanConfig.LaserStyle laserStyle) {\n        this.laserStyle = laserStyle;\n    }\n\n    /**\n     * 背景色\n     *\n     * @param maskColor\n     */\n    public void setMaskColor(int maskColor) {\n        this.maskColor = maskColor;\n    }\n\n    /**\n     * 网格扫描列数\n     *\n     * @param gridColumn\n     */\n    public void setGridScannerColumn(int gridColumn) {\n        if (gridColumn > 0) {\n            this.gridColumn = gridColumn;\n        }\n    }\n\n    /**\n     * 网格扫描高度，默认扫描框的高度\n     *\n     * @param gridHeight\n     */\n    public void setGridScannerHeight(int gridHeight) {\n        this.gridHeight = gridHeight;\n    }\n\n\n    public void setScanConfig(MNScanConfig scanConfig) {\n        this.mnScanConfig = scanConfig;\n\n        //扫描文字配置\n        setHintText(mnScanConfig.getScanHintText(), mnScanConfig.getScanHintTextColor(), mnScanConfig.getScanHintTextSize());\n\n        //扫描线相关配置\n        if (!TextUtils.isEmpty(mnScanConfig.getScanColor())) {\n            setLaserColor(Color.parseColor(mnScanConfig.getScanColor()));\n        }\n        setLaserStyle(mnScanConfig.getLaserStyle());\n\n        if (!TextUtils.isEmpty(mnScanConfig.getBgColor())) {\n            setMaskColor(Color.parseColor(mnScanConfig.getBgColor()));\n        }\n        setGridScannerColumn(mnScanConfig.getGridScanLineColumn());\n        setGridScannerHeight(mnScanConfig.getGridScanLineHeight());\n    }\n\n    /**\n     * 设置文案\n     */\n    public void setHintText(String hintMsg, String hintTextColor, int hintTextSize) {\n        //文字\n        if (!TextUtils.isEmpty(hintMsg)) {\n            this.hintMsg = hintMsg;\n        } else {\n            this.hintMsg = \"\";\n        }\n        //文字颜色\n        if (!TextUtils.isEmpty(hintTextColor)) {\n            this.hintTextColor = hintTextColor;\n        }\n        //文字大小\n        if (hintTextSize > 0) {\n            this.hintTextSize = hintTextSize;\n        }\n        paintText.setColor(Color.parseColor(this.hintTextColor));\n        paintText.setTextSize(CommonUtils.sp2px(getContext(), this.hintTextSize));\n    }\n\n    @SuppressLint(\"DrawAllocation\")\n    @Override\n    public void onDraw(Canvas canvas) {\n        int width = canvas.getWidth();\n        int height = canvas.getHeight();\n        int txtMargin = CommonUtils.dip2px(getContext(), 20);\n\n        int frameWidth = (int) (width * this.mnScanConfig.getScanFrameSizeScale());\n        if (mnScanConfig != null && mnScanConfig.isFullScreenScan()) {\n            frameWidth = width * 9 / 10;\n        }\n        int left = (width - frameWidth) / 2;\n        int top = (height - frameWidth) / 2;\n        frame = new Rect(left, top, left + frameWidth, top + frameWidth);\n\n        //重新赋值\n        frame.top = (height - (frame.right - frame.left)) / 2;\n        frame.bottom = frame.top + (frame.right - frame.left);\n        frame.left = (width - (frame.right - frame.left)) / 2;\n        frame.right = frame.left + (frame.right - frame.left);\n\n        paintLine.setShader(null);\n        //四角线块\n        int rectH = cornerLineW;\n        int rectW = cornerLineH;\n        //判断是不是全屏模式\n        if (mnScanConfig != null && mnScanConfig.isFullScreenScan()) {\n            //全屏透明\n            paint.setColor(Color.TRANSPARENT);\n            canvas.drawRect(0, 0, width, height, paint);\n            //扫描线的宽度\n            laserLineW = CommonUtils.dip2px(getContext(), 4);\n        } else {\n            //扫描线的宽度\n            laserLineW = CommonUtils.dip2px(getContext(), 2);\n            // 半透明背景\n            paint.setColor(maskColor);\n\n            canvas.drawRect(0, 0, width, frame.top, paint);\n            canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);\n            canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);\n            canvas.drawRect(0, frame.bottom + 1, width, height, paint);\n            //左上角\n            canvas.drawRect(frame.left, frame.top, frame.left + rectW, frame.top + rectH, paintLine);\n            canvas.drawRect(frame.left, frame.top, frame.left + rectH, frame.top + rectW, paintLine);\n            //右上角\n            canvas.drawRect(frame.right - rectW, frame.top, frame.right + 1, frame.top + rectH, paintLine);\n            canvas.drawRect(frame.right - rectH, frame.top, frame.right + 1, frame.top + rectW, paintLine);\n            //左下角\n            canvas.drawRect(frame.left, frame.bottom - rectH, frame.left + rectW, frame.bottom + 1, paintLine);\n            canvas.drawRect(frame.left, frame.bottom - rectW, frame.left + rectH, frame.bottom + 1, paintLine);\n            //右下角\n            canvas.drawRect(frame.right - rectW, frame.bottom - rectH, frame.right + 1, frame.bottom + 1, paintLine);\n            canvas.drawRect(frame.right - rectH, frame.bottom - rectW, frame.right + 1, frame.bottom + 1, paintLine);\n        }\n\n        //带有背景框的文字，暂时不做\n//        float textWidth = CommonUtils.getTextWidth(hintMsg, paintText);\n//        float textHeight = CommonUtils.getTextHeight(hintMsg, paintText);\n//        float startX = (width - textWidth) / 2 - CommonUtils.dip2px(getContext(), 20);\n//        float startY = frame.bottom + txtMargin;\n//        float endX = startX + textWidth + CommonUtils.dip2px(getContext(), 40);\n//        float endY = startY + textHeight + CommonUtils.dip2px(getContext(), 12);\n//        RectF rectF = new RectF(startX, startY, endX, endY);\n//        canvas.drawRoundRect(rectF, 100, 100, paintTextBg);\n//        if (mnScanConfig.isSupportZoom() && mnScanConfig.isShowZoomController() && mnScanConfig.getZoomControllerLocation() == MNScanConfig.ZoomControllerLocation.Bottom) {\n//            canvas.drawText(hintMsg, width / 2, frame.top - txtMargin, paintText);\n//        } else {\n//            canvas.drawText(hintMsg, width / 2, startY + (rectF.height() - textHeight) + (rectF.height() - textHeight) / 2f, paintText);\n//        }\n        //文字\n        canvas.drawText(hintMsg, width / 2, frame.bottom + txtMargin + CommonUtils.getTextHeight(hintMsg, paintText), paintText);\n\n        //中间的线：动画\n        if (linePosition <= 0) {\n            linePosition = frame.top + margin;\n        }\n        //扫描线\n        if (laserStyle == MNScanConfig.LaserStyle.Line) {\n            drawLineScanner(canvas, frame);\n        } else if (laserStyle == MNScanConfig.LaserStyle.Grid) {\n            drawGridScanner(canvas, frame);\n        }\n        //动画刷新\n        startAnimation();\n    }\n\n    /**\n     * 绘制线性式扫描\n     *\n     * @param canvas\n     * @param frame\n     */\n    private void drawLineScanner(Canvas canvas, Rect frame) {\n        //线性渐变\n        LinearGradient linearGradient = new LinearGradient(\n                frame.left, linePosition,\n                frame.left, linePosition + laserLineW,\n                shadeColor(laserColor),\n                laserColor,\n                Shader.TileMode.MIRROR);\n        paintLine.setShader(linearGradient);\n        RectF rect = new RectF(frame.left + margin, linePosition, frame.right - margin, linePosition + laserLineW);\n        canvas.drawOval(rect, paintLaser);\n    }\n\n    /**\n     * 绘制网格式扫描\n     *\n     * @param canvas\n     * @param frame\n     */\n    private void drawGridScanner(Canvas canvas, Rect frame) {\n        if (gridHeight <= 0) {\n            gridHeight = frame.bottom - frame.top;\n        }\n        int stroke = 2;\n        paintLaser.setStrokeWidth(stroke);\n        //计算Y轴开始位置\n        int startY;\n        if (gridHeight > 0 && linePosition - frame.top > gridHeight) {\n            startY = linePosition - gridHeight;\n        } else {\n            startY = frame.top;\n        }\n\n        LinearGradient linearGradient = new LinearGradient(frame.left + frame.width() / 2, startY, frame.left + frame.width() / 2, linePosition, new int[]{shadeColor(laserColor), laserColor}, new float[]{0, 1f}, LinearGradient.TileMode.CLAMP);\n        //给画笔设置着色器\n        paintLaser.setShader(linearGradient);\n\n        float wUnit = frame.width() * 1.0f / gridColumn;\n        float hUnit = wUnit;\n        //遍历绘制网格纵线\n        for (int i = 0; i <= gridColumn; i++) {\n            float startX;\n            float stopX;\n            if (i == 0) {\n                startX = frame.left + 1;\n            } else if (i == gridColumn) {\n                startX = frame.left + i * wUnit - 1;\n            } else {\n                startX = frame.left + i * wUnit;\n            }\n            stopX = startX;\n            canvas.drawLine(startX, startY, stopX, linePosition, paintLaser);\n        }\n        int height = gridHeight > 0 && linePosition - frame.top > gridHeight ? gridHeight : linePosition - frame.top;\n        //遍历绘制网格横线\n        for (int i = 0; i <= height / hUnit; i++) {\n            canvas.drawLine(frame.left, linePosition - i * hUnit, frame.right, linePosition - i * hUnit, paintLaser);\n        }\n    }\n\n    /**\n     * 处理颜色模糊\n     *\n     * @param color\n     * @return\n     */\n    public int shadeColor(int color) {\n        String hax = Integer.toHexString(color);\n        String result = \"01\" + hax.substring(2);\n        return Integer.valueOf(result, 16);\n    }\n\n    public void startAnimation() {\n        if (anim != null) {\n            return;\n        }\n        anim = ValueAnimator.ofInt(frame.top - 2, frame.bottom + 2);\n        anim.setRepeatCount(ValueAnimator.INFINITE);\n        anim.setRepeatMode(ValueAnimator.RESTART);\n        anim.setDuration(2400);\n        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {\n            @Override\n            public void onAnimationUpdate(ValueAnimator animation) {\n                if (!needAnimation) {\n                    return;\n                }\n                linePosition = (int) animation.getAnimatedValue();\n                try {\n                    postInvalidate(\n                            frame.left - 2,\n                            frame.top - 2,\n                            frame.right + 2,\n                            frame.bottom + 2);\n                } catch (Exception e) {\n                    postInvalidate();\n                }\n            }\n        });\n        anim.start();\n    }\n\n    public void destroyView() {\n        if (anim != null) {\n            anim.removeAllUpdateListeners();\n            anim.cancel();\n            anim.end();\n            anim = null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "mlkit-scanner/src/main/res/anim/mn_scan_activity_bottom_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:duration=\"300\">\n\n    <alpha\n        android:duration=\"200\"\n        android:fromAlpha=\"0\"\n        android:toAlpha=\"1\" />\n\n    <translate\n        android:duration=\"200\"\n        android:fromYDelta=\"100%p\"\n        android:toYDelta=\"0\" />\n\n</set>"
  },
  {
    "path": "mlkit-scanner/src/main/res/anim/mn_scan_activity_bottom_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <alpha\n        android:duration=\"200\"\n        android:fromAlpha=\"1\"\n        android:toAlpha=\"0.5\" />\n\n    <translate\n        android:duration=\"200\"\n        android:fromYDelta=\"0\"\n        android:toYDelta=\"100%p\" />\n\n</set>"
  },
  {
    "path": "mlkit-scanner/src/main/res/drawable/mn_scan_result_point_default.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <size\n        android:width=\"36dp\"\n        android:height=\"36dp\" />\n\n    <!-- 填充的颜色 -->\n    <solid android:color=\"@color/mn_scan_viewfinder_laser_result_point\" />\n\n    <stroke\n        android:width=\"3dp\"\n        android:color=\"@color/mn_scan_viewfinder_laser_result_point_border\" />\n\n    <corners android:radius=\"36dp\" />\n\n</shape>"
  },
  {
    "path": "mlkit-scanner/src/main/res/layout/mn_scan_action_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--LoadingDialog-->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:background=\"#000000\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <!--菜单-->\n        <RelativeLayout\n            android:id=\"@+id/rl_default_menu\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n            <!--闪光灯-->\n            <LinearLayout\n                android:id=\"@+id/btn_scan_light\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_centerHorizontal=\"true\"\n                android:layout_marginBottom=\"20dp\"\n                android:gravity=\"center\"\n                android:orientation=\"vertical\">\n\n                <ImageView\n                    android:id=\"@+id/iv_scan_light\"\n                    android:layout_width=\"24dp\"\n                    android:layout_height=\"24dp\"\n                    android:src=\"@drawable/mn_icon_scan_flash_light_off\" />\n\n                <TextView\n                    android:id=\"@+id/tv_scan_light\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"6dp\"\n                    android:text=\"打开手电筒\"\n                    android:textColor=\"#FFFFFF\"\n                    android:textSize=\"12dp\" />\n\n            </LinearLayout>\n            <!--关闭-->\n            <LinearLayout\n                android:id=\"@+id/btn_close\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"50dp\"\n                android:gravity=\"center\"\n                android:paddingLeft=\"20dp\"\n                android:paddingRight=\"16dp\">\n\n                <ImageView\n                    android:layout_width=\"26dp\"\n                    android:layout_height=\"26dp\"\n                    android:scaleType=\"centerInside\"\n                    android:src=\"@drawable/mn_icon_scan_close\" />\n\n            </LinearLayout>\n            <!--相册-->\n            <LinearLayout\n                android:id=\"@+id/btn_photo\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"50dp\"\n                android:layout_alignParentRight=\"true\"\n                android:gravity=\"center\"\n                android:paddingLeft=\"16dp\"\n                android:paddingRight=\"20dp\">\n\n                <ImageView\n                    android:layout_width=\"26dp\"\n                    android:layout_height=\"26dp\"\n                    android:scaleType=\"centerInside\"\n                    android:src=\"@drawable/mn_icon_scan_photo\" />\n\n            </LinearLayout>\n        </RelativeLayout>\n\n        <!--自定义遮罩-->\n        <LinearLayout\n            android:id=\"@+id/ll_custom_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\"\n            android:visibility=\"gone\">\n\n\n        </LinearLayout>\n\n    </RelativeLayout>\n\n</FrameLayout>\n"
  },
  {
    "path": "mlkit-scanner/src/main/res/layout/mn_scan_activity_scan_preview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/rl_act_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".scan.ui.ScanPreviewActivity\">\n\n    <androidx.camera.view.PreviewView\n        android:id=\"@+id/previewView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n    <com.maning.mlkitscanner.scan.view.ViewfinderView\n        android:id=\"@+id/viewfinderView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n        <View\n            android:id=\"@+id/fakeStatusBar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"20dp\"\n            android:background=\"#00000000\"\n            tools:ignore=\"MissingConstraints\" />\n\n        <!--功能菜单-->\n        <com.maning.mlkitscanner.scan.view.ScanActionMenuView\n            android:id=\"@+id/action_menu_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n\n    </LinearLayout>\n\n    <com.maning.mlkitscanner.scan.view.ScanResultPointView\n        android:id=\"@+id/result_point_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"#000000\"\n        android:visibility=\"gone\" />\n\n</RelativeLayout>"
  },
  {
    "path": "mlkit-scanner/src/main/res/layout/mn_scan_result_point_item_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/rl_root\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    tools:background=\"#000000\">\n\n    <ImageView\n        android:id=\"@+id/iv_point_bg\"\n        android:layout_width=\"36dp\"\n        android:layout_height=\"36dp\"\n        tools:background=\"@drawable/mn_scan_result_point_default\" />\n\n    <ImageView\n        android:id=\"@+id/iv_point_arrow\"\n        android:layout_width=\"20dp\"\n        android:layout_height=\"20dp\"\n        android:layout_centerInParent=\"true\"\n        android:src=\"@drawable/mn_icon_scan_default_result_point_arrow\" />\n\n</RelativeLayout>"
  },
  {
    "path": "mlkit-scanner/src/main/res/layout/mn_scan_result_point_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/rl_result_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"#000000\">\n\n    <ImageView\n        android:id=\"@+id/iv_show_result\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"#000000\" />\n\n    <FrameLayout\n        android:id=\"@+id/fl_result_point_root\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"#80000000\" />\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <View\n            android:id=\"@+id/fakeStatusBar2\"\n            android:layout_width=\"20dp\"\n            android:layout_height=\"1px\"\n            android:background=\"#00000000\"\n            tools:layout_height=\"20dp\" />\n\n        <TextView\n            android:id=\"@+id/tv_cancle\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"44dp\"\n            android:gravity=\"center\"\n            android:paddingLeft=\"20dp\"\n            android:paddingRight=\"20dp\"\n            android:text=\"取消\"\n            android:textColor=\"#FFFFFF\"\n            android:textSize=\"16sp\"\n            android:textStyle=\"bold\"\n            android:visibility=\"visible\" />\n\n    </LinearLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "mlkit-scanner/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"mn_scan_viewfinder_laser\">#FFff3535</color>\n    <color name=\"mn_scan_viewfinder_mask\">#80000000</color>\n    <color name=\"mn_scan_viewfinder_laser_result_point\">#CCFF3535</color>\n    <color name=\"mn_scan_viewfinder_laser_result_point_border\">#FFFFFFFF</color>\n</resources>"
  },
  {
    "path": "mlkit-scanner/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <style name=\"MNScanAnimation\">\n        <item name=\"android:activityOpenEnterAnimation\">@null</item>\n        <item name=\"android:activityOpenExitAnimation\">@null</item>\n        <item name=\"android:activityCloseEnterAnimation\">@null</item>\n        <item name=\"android:activityCloseExitAnimation\">@null</item>\n        <item name=\"android:taskOpenEnterAnimation\">@null</item>\n        <item name=\"android:taskOpenExitAnimation\">@null</item>\n        <item name=\"android:taskCloseEnterAnimation\">@null</item>\n        <item name=\"android:taskCloseExitAnimation\">@null</item>\n        <item name=\"android:taskToFrontEnterAnimation\">@null</item>\n        <item name=\"android:taskToFrontExitAnimation\">@null</item>\n        <item name=\"android:taskToBackEnterAnimation\">@null</item>\n        <item name=\"android:taskToBackExitAnimation\">@null</item>\n    </style>\n\n    <style name=\"MNScanCaptureTheme\" parent=\"Theme.AppCompat.NoActionBar\">\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:windowAnimationStyle\">@style/MNScanAnimation</item>\n        <item name=\"android:windowFullscreen\">false</item>\n        <item name=\"android:windowIsTranslucent\">false</item>\n        <item name=\"android:windowDisablePreview\">true</item>\n    </style>\n\n</resources>"
  },
  {
    "path": "settings.gradle",
    "content": "include ':mlkit-scanner'\ninclude ':app'\nrootProject.name = \"MNMLKitScanner\""
  }
]