Initial commit

This commit is contained in:
Jenly
2018-08-09 16:17:49 +08:00
commit 387082cba8
114 changed files with 6503 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
*.iml
.gradle
/local.properties
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
.DS_Store
/build
/captures
.externalNativeBuild

57
.idea/assetWizardSettings.xml generated Normal file
View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WizardSettings">
<option name="children">
<map>
<entry key="imageWizard">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="imageAssetPanel">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="launcher">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="foregroundImage">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="scalingPercent" value="46" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
<option name="values">
<map>
<entry key="backgroundAssetType" value="COLOR" />
<entry key="backgroundColor" value="1fb3e2" />
<entry key="foregroundImage" value="C:\code_icon(1).png" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</component>
</project>

BIN
.idea/caches/build_file_checksums.ser generated Normal file

Binary file not shown.

29
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,29 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
</code_scheme>
</component>

6
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

19
.idea/gradle.xml generated Normal file
View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/lib" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

78
.idea/markdown-navigator.xml generated Normal file
View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownProjectSettings" wasCopied="true">
<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="true" showSelectionInPreview="true" openRemoteLinks="true" replaceUnicodeEmoji="false" lastLayoutSetsDefault="false">
<PanelProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
</PanelProvider>
</PreviewSettings>
<ParserSettings gitHubSyntaxChange="false" emojiShortcuts="0" emojiImages="0">
<PegdownExtensions>
<option name="ABBREVIATIONS" value="false" />
<option name="ANCHORLINKS" value="true" />
<option name="ASIDE" value="false" />
<option name="ATXHEADERSPACE" value="true" />
<option name="AUTOLINKS" value="true" />
<option name="DEFINITIONS" value="false" />
<option name="DEFINITION_BREAK_DOUBLE_BLANK_LINE" value="false" />
<option name="FENCED_CODE_BLOCKS" value="true" />
<option name="FOOTNOTES" value="false" />
<option name="HARDWRAPS" value="false" />
<option name="HTML_DEEP_PARSER" value="false" />
<option name="INSERTED" value="false" />
<option name="QUOTES" value="false" />
<option name="RELAXEDHRULES" value="true" />
<option name="SMARTS" value="false" />
<option name="STRIKETHROUGH" value="true" />
<option name="SUBSCRIPT" value="false" />
<option name="SUPERSCRIPT" value="false" />
<option name="SUPPRESS_HTML_BLOCKS" value="false" />
<option name="SUPPRESS_INLINE_HTML" value="false" />
<option name="TABLES" value="true" />
<option name="TASKLISTITEMS" value="true" />
<option name="TOC" value="false" />
<option name="WIKILINKS" value="true" />
</PegdownExtensions>
<ParserOptions>
<option name="ADMONITION_EXT" value="false" />
<option name="ATTRIBUTES_EXT" value="false" />
<option name="COMMONMARK_LISTS" value="false" />
<option name="DUMMY" value="false" />
<option name="EMOJI_SHORTCUTS" value="true" />
<option name="ENUMERATED_REFERENCES_EXT" value="false" />
<option name="FLEXMARK_FRONT_MATTER" value="false" />
<option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="true" />
<option name="GFM_TABLE_RENDERING" value="true" />
<option name="GITBOOK_URL_ENCODING" value="false" />
<option name="GITHUB_LISTS" value="true" />
<option name="GITHUB_WIKI_LINKS" value="true" />
<option name="HEADER_ID_NO_DUPED_DASHES" value="false" />
<option name="JEKYLL_FRONT_MATTER" value="false" />
<option name="NO_TEXT_ATTRIBUTES" value="false" />
<option name="PARSE_HTML_ANCHOR_ID" value="false" />
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
</ParserOptions>
</ParserSettings>
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true" embedImages="false" embedHttpImages="false" imageUriSerials="false">
<GeneratorProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
</GeneratorProvider>
<headerTop />
<headerBottom />
<bodyTop />
<bodyBottom />
</HtmlSettings>
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="false" isCssTextEnabled="false" isDynamicPageWidth="true">
<StylesheetProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" />
</StylesheetProvider>
<ScriptProviders />
<cssText />
<cssUriHistory />
</CssSettings>
<HtmlExportSettings updateOnSave="false" parentDir="$ProjectFileDir$" targetDir="$ProjectFileDir$" cssDir="" scriptDir="" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetExt="" useTargetExt="false" noCssNoScripts="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" />
<LinkMapSettings>
<textMaps />
</LinkMapSettings>
</component>
</project>

View File

@@ -0,0 +1,3 @@
<component name="MarkdownNavigator.ProfileManager">
<settings default="" pdf-export="" />
</component>

34
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="5">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

12
.idea/runConfigurations.xml generated Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

28
.travis.yml Normal file
View File

@@ -0,0 +1,28 @@
language: android
jdk: oraclejdk8
before_install:
- yes | sdkmanager "platforms;android-27"
env:
global:
- ANDROID_API_LEVEL=27
- ANDROID_BUILD_TOOLS_VERSION=27.0.3
- TRAVIS_SECURE_ENV_VARS=true
android:
components:
# The BuildTools version used by your project
- tools
- platform-tools
- build-tools-$ANDROID_BUILD_TOOLS_VERSION
- extra-android-m2repository
- extra-google-android-support
# The SDK version used to compile your project
- android-$ANDROID_API_LEVEL
licenses:
- '.+'
script:
- ./gradlew clean
- ./gradlew assembleDebug

BIN
GIF.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 MiB

201
LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

112
README.md Normal file
View File

@@ -0,0 +1,112 @@
# ZXingLite
![Image](app/src/main/ic_launcher-web.png)
[![Download](https://img.shields.io/badge/download-App-blue.svg)](https://raw.githubusercontent.com/jenly1314/ZXingLite/master/app/release/app-release.apk)
[![](https://jitpack.io/v/jenly1314/ZXingLite.svg)](https://jitpack.io/#jenly1314/ZXingLite)
[![CI](https://travis-ci.org/jenly1314/ZXingLite.svg?branch=master)](https://travis-ci.org/jenly1314/ZXingLite)
[![API](https://img.shields.io/badge/API-15%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=15)
[![License](https://img.shields.io/badge/license-Apche%202.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0)
[![Blog](https://img.shields.io/badge/blog-Jenly-9933CC.svg)](http://blog.csdn.net/jenly121)
ZXingLite for Android 是ZXing的精简版优化扫码和生成二维码功能扫码界面支持完全自定义让集成更简单。
## Gif 展示
![Image](GIF.gif)
## ViewfinderView属性说明
| 属性 | 值类型 | 默认值 | 说明 |
| :------| :------ | :------ | :------ |
| maskColor | color |<font color=#000000>#60000000</font>| 扫描区外遮罩的颜色 |
| frameColor | color |<font color=#1FB3E2>#7F1FB3E2</font>| 扫描区边框的颜色 |
| cornerColor | color |<font color=#1FB3E2>#FF1FB3E2</font>| 扫描区边角的颜色 |
| laserColor | color |<font color=#1FB3E2>#FF1FB3E2</font>| 扫描区激光线的颜色 |
| resultPointColor | color |<font color=#EFBD21>#C0EFBD21</font>| 扫描区结果点的颜色 |
| text | string || 扫描提示文本信息 |
| textColor | color |<font color=#C0C0C0>#FFC0C0C0</font>| 提示文本字体颜色 |
| textSize | dimension |14sp| 提示文本字体大小 |
| textPadding | dimension |24dp| 提示文本距离扫描区的间距 |
| textLocation | enum |top| 提示文本信息显示的位置 |
## 引入
### Maven
```maven
<dependency>
<groupId>com.king.zxing</groupId>
<artifactId>zxing-lite</artifactId>
<version>1.0.0</version>
<type>pom</type>
</dependency>
```
### Gradle:
```gradle
implementation 'com.king.zxing:zxing-lite:1.0.0'
```
### Lvy:
```lvy
<dependency org='com.king.zxing' name='zxing-lite' rev='1.0.0'>
<artifact name='$AID' ext='pom'></artifact>
</dependency>
```
###### 如果Gradle出现compile失败的情况可以在Project的build.gradle里面添加如下也可以使用上面的GitPack来complie
```gradle
allprojects {
repositories {
maven { url 'https://dl.bintray.com/jenly/maven' }
}
}
```
## 引入的库:
```gradle
compileOnly 'com.android.support:appcompat-v7:27.1.1'
api 'com.com.google.zxing:core:3.3.3'
```
## 示例
布局示例 可自定义布局布局内至少要保证有SurfaceView和ViewfinderView控件id可根据重写CaptureActivity 的 getPreviewViewId 和 getViewFinderViewId方法自定义
```Xml
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<SurfaceView
android:id="@+id/preview_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.king.zxing.ViewfinderView
android:id="@+id/viewfinder_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</merge>
```
代码示例 (二维码/条形码)
```Java
//生成二维码
CodeUtils.createQRCode(content,600,logo);
//生成条形码
CodeUtils.createBarCode(content, BarcodeFormat.CODE_128,800,200);
```
更多使用详情,请查看[app](app)中的源码使用示例
## 关于我
Name: <a title="关于作者" href="https://about.me/jenly1314" target="_blank">Jenly</a>
Email: <a title="欢迎邮件与我交流" href="mailto:jenly1314@gmail.com" target="_blank">jenly1314#gmail.com</a> / <a title="给我发邮件" href="mailto:jenly1314@vip.qq.com" target="_blank">jenly1314#vip.qq.com</a>
CSDN: <a title="CSDN博客" href="http://blog.csdn.net/jenly121" target="_blank">jenly121</a>
Github: <a title="Github开源项目" href="https://github.com/jenly1314" target="_blank">jenly1314</a>
微信公众号:
![公众号](http://olambmg9j.bkt.clouddn.com/jenly666.jpg)
加入QQ群: <a title="点击加入QQ群" href="http://shang.qq.com/wpa/qunwpa?idkey=8fcc6a2f88552ea44b1411582c94fd124f7bb3ec227e2a400dbbfaad3dc2f5ad" target="_blank">20867961</a>

1
app/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

36
app/build.gradle Normal file
View File

@@ -0,0 +1,36 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion build_versions.compileSdk
buildToolsVersion build_versions.buildTools
defaultConfig {
applicationId "com.king.zxing.app"
minSdkVersion build_versions.minSdk
targetSdkVersion build_versions.targetSdk
versionCode app_version.versionCode
versionName app_version.versionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
testImplementation deps.test.junit
androidTestImplementation deps.test.runner
androidTestImplementation deps.test.espresso
//support
implementation deps.support.design
implementation deps.support.appcompat
implementation deps.support.constraintlayout
implementation deps.easypermissions
implementation project(':lib')
}

21
app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

BIN
app/release/app-release.apk Normal file

Binary file not shown.

1
app/release/output.json Normal file
View File

@@ -0,0 +1 @@
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]

View File

@@ -0,0 +1,26 @@
package com.king.zxing.app;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.king.zxing.app", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.king.zxing.app">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".EasyCaptureActivity"
android:screenOrientation="portrait"/>
<activity
android:name=".CustomCaptureActivity"
android:screenOrientation="portrait"/>
<activity
android:name=".CodeActivity"
android:screenOrientation="portrait"/>
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2018 Jenly Yu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.king.zxing.app;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.zxing.BarcodeFormat;
import com.king.zxing.util.CodeUtils;
/**
* @author Jenly <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/
public class CodeActivity extends AppCompatActivity {
private TextView tvTitle;
private ImageView ivCode;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.code_activity);
ivCode = findViewById(R.id.ivCode);
tvTitle = findViewById(R.id.tvTitle);
tvTitle.setText(getIntent().getStringExtra(MainActivity.KEY_TITLE));
boolean isQRCode = getIntent().getBooleanExtra(MainActivity.KEY_IS_QR_CODE,false);
if(isQRCode){
createQRCode(getString(R.string.app_name));
}else{
createBarCode(getString(R.string.app_name));
}
}
/**
* 生成二维码
* @param content
*/
private void createQRCode(String content){
//生成二维码最好放子线程生成防止阻塞UI这里只是演示
Bitmap logo = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
Bitmap bitmap = CodeUtils.createQRCode(content,600,logo);
//显示二维码
ivCode.setImageBitmap(bitmap);
}
/**
* 生成条形码
* @param content
*/
private void createBarCode(String content){
//生成条形码最好放子线程生成防止阻塞UI这里只是演示
Bitmap bitmap = CodeUtils.createBarCode(content, BarcodeFormat.CODE_128,800,200);
//显示条形码
ivCode.setImageBitmap(bitmap);
}
public void OnClick(View v){
switch (v.getId()){
case R.id.ivLeft:
onBackPressed();
break;
}
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2018 Jenly Yu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.king.zxing.app;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.TextView;
import com.king.zxing.CaptureActivity;
import com.king.zxing.app.util.StatusBarUtils;
/**
* @author Jenly <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/
public class CustomCaptureActivity extends CaptureActivity {
@Override
public int getLayoutId() {
return R.layout.custom_capture_activity;
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Toolbar toolbar = findViewById(R.id.toolbar);
StatusBarUtils.immersiveStatusBar(this,toolbar,0.2f);
TextView tvTitle = findViewById(R.id.tvTitle);
tvTitle.setText(getIntent().getStringExtra(MainActivity.KEY_TITLE));
getBeepManager().setPlayBeep(true);
getBeepManager().setVibrate(true);
}
private void offFlash(){
Camera camera = getCameraManager().getOpenCamera().getCamera();
Camera.Parameters parameters = camera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(parameters);
}
public void openFlash(){
Camera camera = getCameraManager().getOpenCamera().getCamera();
Camera.Parameters parameters = camera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameters);
}
private void clickFlash(View v){
if(v.isSelected()){
offFlash();
v.setSelected(false);
}else{
openFlash();
v.setSelected(true);
}
}
public void OnClick(View v){
switch (v.getId()){
case R.id.ivLeft:
onBackPressed();
break;
case R.id.ivFlash:
clickFlash(v);
break;
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2018 Jenly Yu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.king.zxing.app;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.TextView;
import com.king.zxing.CaptureActivity;
import com.king.zxing.app.util.StatusBarUtils;
/**
* @author Jenly <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/
public class EasyCaptureActivity extends CaptureActivity {
@Override
public int getLayoutId() {
return R.layout.easy_capture_activity;
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Toolbar toolbar = findViewById(R.id.toolbar);
StatusBarUtils.immersiveStatusBar(this,toolbar,0.2f);
TextView tvTitle = findViewById(R.id.tvTitle);
tvTitle.setText(getIntent().getStringExtra(MainActivity.KEY_TITLE));
}
public void OnClick(View v){
switch (v.getId()){
case R.id.ivLeft:
onBackPressed();
break;
}
}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright (C) 2018 Jenly Yu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.king.zxing.app;
import android.Manifest;
import android.content.Intent;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.king.zxing.CaptureActivity;
import com.king.zxing.Intents;
import java.util.List;
import pub.devrel.easypermissions.AfterPermissionGranted;
import pub.devrel.easypermissions.EasyPermissions;
public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks{
public static final String KEY_TITLE = "key_title";
public static final String KEY_IS_QR_CODE = "key_code";
public static final int REQUEST_CODE = 0X01;
public static final int RC_CAMERA = 0X01;
private Class<?> cls;
private String title;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
if(data!=null){
//识别结果
String result = data.getStringExtra(Intents.Scan.RESULT);
Toast.makeText(this,result,Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// Forward results to EasyPermissions
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@Override
public void onPermissionsGranted(int requestCode, List<String> list) {
// Some permissions have been granted
startScan(cls,title);
}
@Override
public void onPermissionsDenied(int requestCode, List<String> list) {
// Some permissions have been denied
// ...
}
/**
* 检测拍摄权限
* @param cls
* @param title
*/
@AfterPermissionGranted(RC_CAMERA)
private void checkCameraPermissions(Class<?> cls,String title){
this.cls = cls;
this.title = title;
String[] perms = {Manifest.permission.CAMERA};
if (EasyPermissions.hasPermissions(this, perms)) {//有权限
startScan(cls,title);
} else {
// Do not have permissions, request them now
EasyPermissions.requestPermissions(this, getString(R.string.permission_camera),
RC_CAMERA, perms);
}
}
/**
* 扫码
* @param cls
* @param title
*/
private void startScan(Class<?> cls,String title){
ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeCustomAnimation(this,R.anim.in,R.anim.out);
Intent intent = new Intent(this, cls);
intent.putExtra(KEY_TITLE,title);
ActivityCompat.startActivityForResult(this,intent,REQUEST_CODE,optionsCompat.toBundle());
}
/**
* 生成二维码/条形码
* @param isQRCode
*/
private void startCode(boolean isQRCode){
Intent intent = new Intent(this,CodeActivity.class);
intent.putExtra(KEY_IS_QR_CODE,isQRCode);
intent.putExtra(KEY_TITLE,isQRCode ? getString(R.string.qr_code) : getString(R.string.bar_code));
startActivity(intent);
}
public void OnClick(View v){
switch (v.getId()){
case R.id.btn1:
checkCameraPermissions(CaptureActivity.class, ((Button)v).getText().toString());
break;
case R.id.btn2:
checkCameraPermissions(EasyCaptureActivity.class,((Button)v).getText().toString());
break;
case R.id.btn3:
checkCameraPermissions(CustomCaptureActivity.class,((Button)v).getText().toString());
break;
case R.id.btn4:
startCode(false);
break;
case R.id.btn5:
startCode(true);
break;
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2018 Jenly Yu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.king.zxing.app.util;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.FloatRange;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import com.king.zxing.app.R;
/**
* @author Jenly <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/
public enum StatusBarUtils {
INSTANCE;
public static void immersiveStatusBar(Activity activity,Toolbar toolbar) {
immersiveStatusBar(activity,toolbar,0.0f);
}
public static void immersiveStatusBar(Activity activity,Toolbar toolbar,@FloatRange(from = 0.0, to = 1.0) float alpha) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
Window window = activity.getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
} else {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
ViewGroup decorView = (ViewGroup) window.getDecorView();
ViewGroup contentView = window.getDecorView().findViewById(Window.ID_ANDROID_CONTENT);
View rootView = contentView.getChildAt(0);
if (rootView != null) {
rootView.setFitsSystemWindows(false);
}
if(toolbar!=null){
toolbar.setPadding(0,getStatusBarHeight(activity),0,0);
}
decorView.addView(createStatusBarView(activity,alpha));
}
private static View createStatusBarView(Activity activity,@FloatRange(from = 0.0, to = 1.0) float alpha) {
// 绘制一个和状态栏一样高的矩形
View statusBarView = new View(activity);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
statusBarView.setLayoutParams(params);
statusBarView.setBackgroundColor(Color.argb((int) (alpha * 255), 0, 0, 0));
statusBarView.setId(R.id.translucent_view);
return statusBarView;
}
/** 获取状态栏高度 */
public static int getStatusBarHeight(Context context) {
return context.getResources().getDimensionPixelSize(R.dimen.status_bar_height);
}
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0.2"
android:toAlpha="1.0"
android:duration="200" />

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="200" />

View File

@@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0"/>
<item
android:color="#00000000"
android:offset="1.0"/>
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 B

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/btn_back_pressed"/>
<item android:state_pressed="false" android:drawable="@drawable/btn_back_normal"/>
</selector>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="@drawable/flash_on"/>
<item android:state_selected="false" android:drawable="@drawable/flash_off"/>
</selector>

View File

@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z"/>
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
</vector>

View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:background="@color/colorPrimary"
android:layout_height="wrap_content"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="@dimen/title_height"
android:gravity="center"
android:singleLine="true"
android:textSize="@dimen/size_18sp"
android:textColor="@color/white"
android:layout_gravity="center_horizontal"
android:text="@string/app_name"/>
</android.support.v7.widget.Toolbar>
<android.support.constraint.Guideline
android:id="@+id/line"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:layout_constraintGuide_percent="0.2"/>
<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:text="默认扫码"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/line"
style="@style/OnClick"/>
<Button
android:id="@+id/btn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:text="简单自定义布局扫码"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn1"
style="@style/OnClick"/>
<Button
android:id="@+id/btn3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:text="自定义布局扫码"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn2"
style="@style/OnClick"/>
<Button
android:id="@+id/btn4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:text="生成条形码"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn3"
style="@style/OnClick"/>
<Button
android:id="@+id/btn5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:text="生成二维码"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn4"
style="@style/OnClick"/>
</android.support.constraint.ConstraintLayout>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<include android:id="@+id/toolbar"
layout="@layout/toolbar"/>
<ImageView
android:id="@+id/ivCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/preview_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.king.zxing.ViewfinderView
android:id="@+id/viewfinder_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:text="@string/tips_scan_code"
app:textSize="@dimen/size_14sp"
app:laserColor="@color/colorAccent"
app:frameColor="@color/colorPrimary"
app:cornerColor="@color/colorPrimary"
app:resultPointColor="@color/colorAccent"
app:textLocation="bottom"/>
<ImageView
android:id="@+id/ivFlash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/flash_selected_selector"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="160dp"
style="@style/OnClick"/>
<include layout="@layout/toolbar_capture"/>
</android.support.constraint.ConstraintLayout>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/capture"/>
<include layout="@layout/toolbar_capture"/>
</android.support.constraint.ConstraintLayout>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:background="@color/colorPrimary"
android:layout_height="wrap_content"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp">
<include layout="@layout/top_title_back_bar"/>
</android.support.v7.widget.Toolbar>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp">
<include layout="@layout/top_title_back_bar"/>
</android.support.v7.widget.Toolbar>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ll"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="@dimen/title_height"
android:gravity="center">
<ImageView
android:id="@+id/ivLeft"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="@drawable/btn_back_selector"
android:paddingLeft="@dimen/size_14dp"
android:paddingRight="@dimen/size_14dp"
style="@style/OnClick"/>
<TextView
android:id="@+id/tvTitle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:singleLine="true"
android:textSize="@dimen/size_18sp"
android:textColor="@color/white"
android:layout_gravity="center_horizontal"
android:text="@string/app_name"/>
<ImageView
android:id="@+id/ivRight"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/size_14dp"
android:paddingRight="@dimen/size_14dp"
android:src="@drawable/btn_none"
style="@style/OnClick"/>
</LinearLayout>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="status_bar_height">25dp</dimen>
</resources>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="white">#ffffff</color>
</resources>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="status_bar_height">0dp</dimen>
<dimen name="title_height">50dp</dimen>
<dimen name="size_14sp">14sp</dimen>
<dimen name="size_16sp">16sp</dimen>
<dimen name="size_18sp">18sp</dimen>
<dimen name="size_14dp">14dp</dimen>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#1FB3E2</color>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="statusbar_view" type="id"/>
<item name="translucent_view" type="id"/>
</resources>

View File

@@ -0,0 +1,7 @@
<resources>
<string name="app_name">ZXingLite</string>
<string name="permission_camera">App扫码需要用到拍摄权限</string>
<string name="tips_scan_code">将二维码/条形码放入框内,即可自动扫码</string>
<string name="qr_code">二维码</string>
<string name="bar_code">条形码</string>
</resources>

View File

@@ -0,0 +1,17 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
</style>
<style name="OnClick">
<item name="android:clickable">true</item>
<item name="android:onClick">OnClick</item>
</style>
</resources>

View File

@@ -0,0 +1,17 @@
package com.king.zxing.app;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

37
build.gradle Normal file
View File

@@ -0,0 +1,37 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
apply from: 'versions.gradle'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.novoda:bintray-release:0.8.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
addRepos(repositories)
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
allprojects {
tasks.withType(Javadoc) {
options{
encoding "UTF-8"
charSet 'UTF-8'
links "http://docs.oracle.com/javase/8/docs/api"
}
}
}

13
gradle.properties Normal file
View File

@@ -0,0 +1,13 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs = -Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Mon Aug 06 16:59:20 CST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

172
gradlew vendored Normal file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

1
lib/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

11
lib/bintray.gradle Normal file
View File

@@ -0,0 +1,11 @@
apply plugin: 'com.novoda.bintray-release'
//添加
publish {
userOrg = 'jenly'//bintray.com用户名
groupId = 'com.king.zxing'//jcenter上的路径
artifactId = 'zxing-lite'//项目名称
publishVersion = app_version.versionName//版本号
desc = 'ZXingLite for Android'//描述
website = 'https://github.com/jenly1314/ZXingLite'//网站
}

33
lib/build.gradle Normal file
View File

@@ -0,0 +1,33 @@
apply plugin: 'com.android.library'
apply from: 'bintray.gradle'
android {
compileSdkVersion build_versions.compileSdk
buildToolsVersion build_versions.buildTools
defaultConfig {
minSdkVersion build_versions.minSdk
targetSdkVersion build_versions.targetSdk
versionCode app_version.versionCode
versionName app_version.versionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
testImplementation deps.test.junit
androidTestImplementation deps.test.runner
androidTestImplementation deps.test.espresso
compileOnly deps.support.appcompat
api deps.zxing
}

21
lib/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,26 @@
package com.king.zxing;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.king.zxing.test", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,20 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.king.zxing">
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.FLASHLIGHT"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!-- unavailable in API 23 -->
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<application>
<activity
android:name="com.king.zxing.CaptureActivity"
android:screenOrientation="portrait"/>
</application>
</manifest>

View File

@@ -0,0 +1,88 @@
package com.king.zxing;
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.preference.PreferenceManager;
import com.king.zxing.camera.CameraManager;
import com.king.zxing.camera.FrontLightMode;
/**
* Detects ambient light and switches on the front light when very dark, and off again when sufficiently light.
*
* @author Sean Owen
* @author Nikolaus Huber
*/
final class AmbientLightManager implements SensorEventListener {
private static final float TOO_DARK_LUX = 45.0f;
private static final float BRIGHT_ENOUGH_LUX = 450.0f;
private final Context context;
private CameraManager cameraManager;
private Sensor lightSensor;
AmbientLightManager(Context context) {
this.context = context;
}
void start(CameraManager cameraManager) {
this.cameraManager = cameraManager;
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
if (FrontLightMode.readPref(sharedPrefs) == FrontLightMode.AUTO) {
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
if (lightSensor != null) {
sensorManager.registerListener(this, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
}
}
void stop() {
if (lightSensor != null) {
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
sensorManager.unregisterListener(this);
cameraManager = null;
lightSensor = null;
}
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
float ambientLightLux = sensorEvent.values[0];
if (cameraManager != null) {
if (ambientLightLux <= TOO_DARK_LUX) {
cameraManager.setTorch(true);
} else if (ambientLightLux >= BRIGHT_ENOUGH_LUX) {
cameraManager.setTorch(false);
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// do nothing
}
}

View File

@@ -0,0 +1,136 @@
package com.king.zxing;
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.util.Log;
import java.io.Closeable;
import java.io.IOException;
/**
* Manages beeps and vibrations for {@link CaptureActivity}.
*/
public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable {
private static final String TAG = BeepManager.class.getSimpleName();
private static final float BEEP_VOLUME = 0.10f;
private static final long VIBRATE_DURATION = 200L;
private final Activity activity;
private MediaPlayer mediaPlayer;
private boolean playBeep;
private boolean vibrate;
BeepManager(Activity activity) {
this.activity = activity;
this.mediaPlayer = null;
updatePrefs();
}
public void setVibrate(boolean vibrate){
this.vibrate = vibrate;
}
public void setPlayBeep(boolean playBeep){
this.playBeep = playBeep;
}
synchronized void updatePrefs() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
playBeep = shouldBeep(prefs, activity);
// vibrate = prefs.getBoolean(Preferences.KEY_VIBRATE, false);
if (playBeep && mediaPlayer == null) {
// The volume on STREAM_SYSTEM is not adjustable, and users found it too loud,
// so we now play on the music stream.
activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
mediaPlayer = buildMediaPlayer(activity);
}
}
synchronized void playBeepSoundAndVibrate() {
if (playBeep && mediaPlayer != null) {
mediaPlayer.start();
}
if (vibrate) {
Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(VIBRATE_DURATION);
}
}
private static boolean shouldBeep(SharedPreferences prefs, Context activity) {
boolean shouldPlayBeep = prefs.getBoolean(Preferences.KEY_PLAY_BEEP, true);
if (shouldPlayBeep) {
// See if sound settings overrides this
AudioManager audioService = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE);
if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
shouldPlayBeep = false;
}
}
return shouldPlayBeep;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private MediaPlayer buildMediaPlayer(Context activity) {
MediaPlayer mediaPlayer = new MediaPlayer();
try (AssetFileDescriptor file = activity.getResources().openRawResourceFd(R.raw.beep)) {
mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength());
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(false);
mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
mediaPlayer.prepare();
return mediaPlayer;
} catch (IOException ioe) {
Log.w(TAG, ioe);
mediaPlayer.release();
return null;
}
}
@Override
public synchronized boolean onError(MediaPlayer mp, int what, int extra) {
if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
// we are finished, so put up an appropriate error toast if required and finish
activity.finish();
} else {
// possibly media player error, so release and recreate
close();
updatePrefs();
}
return true;
}
@Override
public synchronized void close() {
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
}
}

View File

@@ -0,0 +1,781 @@
package com.king.zxing;
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.Result;
import com.google.zxing.ResultMetadataType;
import com.king.zxing.camera.CameraManager;
import java.io.IOException;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Map;
/**
* This activity opens the camera and does the actual scanning on a background thread. It draws a
* viewfinder to help the user place the barcode correctly, shows feedback as the image processing
* is happening, and then overlays the results when a scan is successful.
*
* @author dswitkin@google.com (Daniel Switkin)
* @author Sean Owen
*/
public class CaptureActivity extends Activity implements SurfaceHolder.Callback {
public static final String KEY_RESULT = Intents.Scan.RESULT;
private static final String TAG = CaptureActivity.class.getSimpleName();
private static final long DEFAULT_INTENT_RESULT_DURATION_MS = 1500L;
private static final long BULK_MODE_SCAN_DELAY_MS = 1000L;
private static final String[] ZXING_URLS = { "http://zxing.appspot.com/scan", "zxing://scan/" };
private static final Collection<ResultMetadataType> DISPLAYABLE_METADATA_TYPES =
EnumSet.of(ResultMetadataType.ISSUE_NUMBER,
ResultMetadataType.SUGGESTED_PRICE,
ResultMetadataType.ERROR_CORRECTION_LEVEL,
ResultMetadataType.POSSIBLE_COUNTRY);
private CameraManager cameraManager;
private CaptureActivityHandler handler;
private Result savedResultToShow;
private ViewfinderView viewfinderView;
// private TextView statusView;
// private View resultView;
private Result lastResult;
private boolean hasSurface;
// private boolean copyToClipboard;
// private IntentSource source;
// private String sourceUrl;
// private ScanFromWebPageManager scanFromWebPageManager;
private Collection<BarcodeFormat> decodeFormats;
private Map<DecodeHintType,?> decodeHints;
private String characterSet;
// private HistoryManager historyManager;
private InactivityTimer inactivityTimer;
private BeepManager beepManager;
private AmbientLightManager ambientLightManager;
public ViewfinderView getViewfinderView() {
return viewfinderView;
}
public Handler getHandler() {
return handler;
}
public CameraManager getCameraManager() {
return cameraManager;
}
public BeepManager getBeepManager() {
return beepManager;
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(getLayoutId());
hasSurface = false;
inactivityTimer = new InactivityTimer(this);
beepManager = new BeepManager(this);
ambientLightManager = new AmbientLightManager(this);
// PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
}
public int getLayoutId(){
return R.layout.capture;
}
public int getViewFinderViewId(){
return R.id.viewfinder_view;
}
public int getPreviewViewId(){
return R.id.preview_view;
}
/**
* 扫码后声音与震动管理里入口
* @return true表示播放和震动是否播放与震动还得看{@link BeepManager}
*/
public boolean isBeepSoundAndVibrate(){
return true;
}
@Override
protected void onResume() {
super.onResume();
// historyManager must be initialized here to update the history preference
// historyManager = new HistoryManager(this);
// historyManager.trimHistory();
// CameraManager must be initialized here, not in onCreate(). This is necessary because we don't
// want to open the camera driver and measure the screen size if we're going to show the help on
// first launch. That led to bugs where the scanning rectangle was the wrong size and partially
// off screen.
cameraManager = new CameraManager(getApplication());
viewfinderView = findViewById(getViewFinderViewId());
viewfinderView.setCameraManager(cameraManager);
// resultView = findViewById(R.id.result_view);
// statusView = findViewById(R.id.status_view);
handler = null;
lastResult = null;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (prefs.getBoolean(Preferences.KEY_DISABLE_AUTO_ORIENTATION, true)) {
setRequestedOrientation(getCurrentOrientation());
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
}
resetStatusView();
beepManager.updatePrefs();
ambientLightManager.start(cameraManager);
inactivityTimer.onResume();
Intent intent = getIntent();
// copyToClipboard = prefs.getBoolean(Preferences.KEY_COPY_TO_CLIPBOARD, true)
// && (intent == null || intent.getBooleanExtra(Intents.Scan.SAVE_HISTORY, true));
//
// source = IntentSource.NONE;
// sourceUrl = null;
// scanFromWebPageManager = null;
decodeFormats = null;
characterSet = null;
if (intent != null) {
String action = intent.getAction();
String dataString = intent.getDataString();
if (Intents.Scan.ACTION.equals(action)) {
// Scan the formats the intent requested, and return the result to the calling activity.
// source = IntentSource.NATIVE_APP_INTENT;
decodeFormats = DecodeFormatManager.parseDecodeFormats(intent);
decodeHints = DecodeHintManager.parseDecodeHints(intent);
if (intent.hasExtra(Intents.Scan.WIDTH) && intent.hasExtra(Intents.Scan.HEIGHT)) {
int width = intent.getIntExtra(Intents.Scan.WIDTH, 0);
int height = intent.getIntExtra(Intents.Scan.HEIGHT, 0);
if (width > 0 && height > 0) {
cameraManager.setManualFramingRect(width, height);
}
}
if (intent.hasExtra(Intents.Scan.CAMERA_ID)) {
int cameraId = intent.getIntExtra(Intents.Scan.CAMERA_ID, -1);
if (cameraId >= 0) {
cameraManager.setManualCameraId(cameraId);
}
}
// String customPromptMessage = intent.getStringExtra(Intents.Scan.PROMPT_MESSAGE);
// if (customPromptMessage != null) {
// statusView.setText(customPromptMessage);
// }
} else if (dataString != null &&
dataString.contains("http://www.google") &&
dataString.contains("/m/products/scan")) {
// Scan only products and send the result to mobile Product Search.
// source = IntentSource.PRODUCT_SEARCH_LINK;
// sourceUrl = dataString;
decodeFormats = DecodeFormatManager.PRODUCT_FORMATS;
} else if (isZXingURL(dataString)) {
// Scan formats requested in query string (all formats if none specified).
// If a return URL is specified, send the results there. Otherwise, handle it ourselves.
// source = IntentSource.ZXING_LINK;
// sourceUrl = dataString;
Uri inputUri = Uri.parse(dataString);
// scanFromWebPageManager = new ScanFromWebPageManager(inputUri);
decodeFormats = DecodeFormatManager.parseDecodeFormats(inputUri);
// Allow a sub-set of the hints to be specified by the caller.
decodeHints = DecodeHintManager.parseDecodeHints(inputUri);
}
characterSet = intent.getStringExtra(Intents.Scan.CHARACTER_SET);
}
SurfaceView surfaceView = findViewById(getPreviewViewId());
SurfaceHolder surfaceHolder = surfaceView.getHolder();
if (hasSurface) {
// The activity was paused but not stopped, so the surface still exists. Therefore
// surfaceCreated() won't be called, so init the camera here.
initCamera(surfaceHolder);
} else {
// Install the callback and wait for surfaceCreated() to init the camera.
surfaceHolder.addCallback(this);
}
}
private int getCurrentOrientation() {
int rotation = getWindowManager().getDefaultDisplay().getRotation();
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
switch (rotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_90:
return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
default:
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
}
} else {
switch (rotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_270:
return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
default:
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
}
}
}
private static boolean isZXingURL(String dataString) {
if (dataString == null) {
return false;
}
for (String url : ZXING_URLS) {
if (dataString.startsWith(url)) {
return true;
}
}
return false;
}
@Override
protected void onPause() {
if (handler != null) {
handler.quitSynchronously();
handler = null;
}
inactivityTimer.onPause();
ambientLightManager.stop();
beepManager.close();
cameraManager.closeDriver();
//historyManager = null; // Keep for onActivityResult
if (!hasSurface) {
SurfaceView surfaceView = findViewById(R.id.preview_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
surfaceHolder.removeCallback(this);
}
super.onPause();
}
@Override
protected void onDestroy() {
inactivityTimer.shutdown();
super.onDestroy();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
// if (source == IntentSource.NATIVE_APP_INTENT) {
// setResult(RESULT_CANCELED);
// finish();
// return true;
// }
// if ((source == IntentSource.NONE || source == IntentSource.ZXING_LINK) && lastResult != null) {
// restartPreviewAfterDelay(0L);
// return true;
// }
break;
case KeyEvent.KEYCODE_FOCUS:
case KeyEvent.KEYCODE_CAMERA:
// Handle these events so they don't launch the Camera app
return true;
// Use volume up/down to turn on light
case KeyEvent.KEYCODE_VOLUME_DOWN:
cameraManager.setTorch(false);
return true;
case KeyEvent.KEYCODE_VOLUME_UP:
cameraManager.setTorch(true);
return true;
}
return super.onKeyDown(keyCode, event);
}
// @Override
// public boolean onCreateOptionsMenu(Menu menu) {
// MenuInflater menuInflater = getMenuInflater();
// menuInflater.inflate(R.menu.capture, menu);
// return super.onCreateOptionsMenu(menu);
// }
//
// @Override
// public boolean onOptionsItemSelected(MenuItem item) {
// Intent intent = new Intent(Intent.ACTION_VIEW);
// intent.addFlags(Intents.FLAG_NEW_DOC);
// switch (item.getItemId()) {
// case R.id.menu_share:
// intent.setClassName(this, ShareActivity.class.getName());
// startActivity(intent);
// break;
// case R.id.menu_history:
// intent.setClassName(this, HistoryActivity.class.getName());
// startActivityForResult(intent, HISTORY_REQUEST_CODE);
// break;
// case R.id.menu_settings:
// intent.setClassName(this, PreferencesActivity.class.getName());
// startActivity(intent);
// break;
// case R.id.menu_help:
// intent.setClassName(this, HelpActivity.class.getName());
// startActivity(intent);
// break;
// default:
// return super.onOptionsItemSelected(item);
// }
// return true;
// }
// @Override
// public void onActivityResult(int requestCode, int resultCode, Intent intent) {
// if (resultCode == RESULT_OK && requestCode == HISTORY_REQUEST_CODE && historyManager != null) {
// int itemNumber = intent.getIntExtra(Intents.History.ITEM_NUMBER, -1);
// if (itemNumber >= 0) {
// HistoryItem historyItem = historyManager.buildHistoryItem(itemNumber);
// decodeOrStoreSavedBitmap(null, historyItem.getResult());
// }
// }
// }
private void decodeOrStoreSavedBitmap(Bitmap bitmap, Result result) {
// Bitmap isn't used yet -- will be used soon
if (handler == null) {
savedResultToShow = result;
} else {
if (result != null) {
savedResultToShow = result;
}
if (savedResultToShow != null) {
Message message = Message.obtain(handler, R.id.decode_succeeded, savedResultToShow);
handler.sendMessage(message);
}
savedResultToShow = null;
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (holder == null) {
Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!");
}
if (!hasSurface) {
hasSurface = true;
initCamera(holder);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
hasSurface = false;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// do nothing
}
/**
* A valid barcode has been found, so give an indication of success and show the results.
*
* @param rawResult The contents of the barcode.
* @param scaleFactor amount by which thumbnail was scaled
* @param barcode A greyscale bitmap of the camera data which was decoded.
*/
public void handleDecode(Result rawResult, Bitmap barcode, float scaleFactor) {
inactivityTimer.onActivity();
lastResult = rawResult;
if(isBeepSoundAndVibrate()){
beepManager.playBeepSoundAndVibrate();
}
String resultString = rawResult.getText();
Intent intent = new Intent();
intent.putExtra(KEY_RESULT,resultString);
setResult(RESULT_OK,intent);
finish();
// ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult);
// boolean fromLiveScan = barcode != null;
// if (fromLiveScan) {
//// historyManager.addHistoryItem(rawResult, resultHandler);
// // Then not from history, so beep/vibrate and we have an image to draw on
// beepManager.playBeepSoundAndVibrate();
// drawResultPoints(barcode, scaleFactor, rawResult);
// }
// switch (source) {
// case NATIVE_APP_INTENT:
// case PRODUCT_SEARCH_LINK:
// handleDecodeExternally(rawResult, resultHandler, barcode);
// break;
// case ZXING_LINK:
// if (scanFromWebPageManager == null || !scanFromWebPageManager.isScanFromWebPage()) {
// handleDecodeInternally(rawResult, resultHandler, barcode);
// } else {
// handleDecodeExternally(rawResult, resultHandler, barcode);
// }
// break;
// case NONE:
// SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
// if (fromLiveScan && prefs.getBoolean(PreferencesActivity.KEY_BULK_MODE, false)) {
// Toast.makeText(getApplicationContext(),
// getResources().getString(R.string.msg_bulk_mode_scanned) + " (" + rawResult.getText() + ')',
// Toast.LENGTH_SHORT).show();
// maybeSetClipboard(resultHandler);
// // Wait a moment or else it will scan the same barcode continuously about 3 times
// restartPreviewAfterDelay(BULK_MODE_SCAN_DELAY_MS);
// } else {
// handleDecodeInternally(rawResult, resultHandler, barcode);
// }
// break;
// }
}
// /**
// * Superimpose a line for 1D or dots for 2D to highlight the key features of the barcode.
// *
// * @param barcode A bitmap of the captured image.
// * @param scaleFactor amount by which thumbnail was scaled
// * @param rawResult The decoded results which contains the points to draw.
// */
// private void drawResultPoints(Bitmap barcode, float scaleFactor, Result rawResult) {
// ResultPoint[] points = rawResult.getResultPoints();
// if (points != null && points.length > 0) {
// Canvas canvas = new Canvas(barcode);
// Paint paint = new Paint();
// paint.setColor(getResources().getColor(R.color.result_points));
// if (points.length == 2) {
// paint.setStrokeWidth(4.0f);
// drawLine(canvas, paint, points[0], points[1], scaleFactor);
// } else if (points.length == 4 &&
// (rawResult.getBarcodeFormat() == BarcodeFormat.UPC_A ||
// rawResult.getBarcodeFormat() == BarcodeFormat.EAN_13)) {
// // Hacky special case -- draw two lines, for the barcode and metadata
// drawLine(canvas, paint, points[0], points[1], scaleFactor);
// drawLine(canvas, paint, points[2], points[3], scaleFactor);
// } else {
// paint.setStrokeWidth(10.0f);
// for (ResultPoint point : points) {
// if (point != null) {
// canvas.drawPoint(scaleFactor * point.getX(), scaleFactor * point.getY(), paint);
// }
// }
// }
// }
// }
//
// private static void drawLine(Canvas canvas, Paint paint, ResultPoint a, ResultPoint b, float scaleFactor) {
// if (a != null && b != null) {
// canvas.drawLine(scaleFactor * a.getX(),
// scaleFactor * a.getY(),
// scaleFactor * b.getX(),
// scaleFactor * b.getY(),
// paint);
// }
// }
//
// // Put up our own UI for how to handle the decoded contents.
// private void handleDecodeInternally(Result rawResult, ResultHandler resultHandler, Bitmap barcode) {
//
// maybeSetClipboard(resultHandler);
//
// SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
//
// if (resultHandler.getDefaultButtonID() != null && prefs.getBoolean(PreferencesActivity.KEY_AUTO_OPEN_WEB, false)) {
// resultHandler.handleButtonPress(resultHandler.getDefaultButtonID());
// return;
// }
//
// statusView.setVisibility(View.GONE);
// viewfinderView.setVisibility(View.GONE);
// resultView.setVisibility(View.VISIBLE);
//
// ImageView barcodeImageView = (ImageView) findViewById(R.id.barcode_image_view);
// if (barcode == null) {
// barcodeImageView.setImageBitmap(BitmapFactory.decodeResource(getResources(),
// R.drawable.launcher_icon));
// } else {
// barcodeImageView.setImageBitmap(barcode);
// }
//
// TextView formatTextView = (TextView) findViewById(R.id.format_text_view);
// formatTextView.setText(rawResult.getBarcodeFormat().toString());
//
// TextView typeTextView = (TextView) findViewById(R.id.type_text_view);
// typeTextView.setText(resultHandler.getType().toString());
//
// DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
// TextView timeTextView = (TextView) findViewById(R.id.time_text_view);
// timeTextView.setText(formatter.format(rawResult.getTimestamp()));
//
//
// TextView metaTextView = (TextView) findViewById(R.id.meta_text_view);
// View metaTextViewLabel = findViewById(R.id.meta_text_view_label);
// metaTextView.setVisibility(View.GONE);
// metaTextViewLabel.setVisibility(View.GONE);
// Map<ResultMetadataType,Object> metadata = rawResult.getResultMetadata();
// if (metadata != null) {
// StringBuilder metadataText = new StringBuilder(20);
// for (Map.Entry<ResultMetadataType,Object> entry : metadata.entrySet()) {
// if (DISPLAYABLE_METADATA_TYPES.contains(entry.getKey())) {
// metadataText.append(entry.getValue()).append('\n');
// }
// }
// if (metadataText.length() > 0) {
// metadataText.setLength(metadataText.length() - 1);
// metaTextView.setText(metadataText);
// metaTextView.setVisibility(View.VISIBLE);
// metaTextViewLabel.setVisibility(View.VISIBLE);
// }
// }
//
// CharSequence displayContents = resultHandler.getDisplayContents();
// TextView contentsTextView = (TextView) findViewById(R.id.contents_text_view);
// contentsTextView.setText(displayContents);
// int scaledSize = Math.max(22, 32 - displayContents.length() / 4);
// contentsTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, scaledSize);
//
// TextView supplementTextView = (TextView) findViewById(R.id.contents_supplement_text_view);
// supplementTextView.setText("");
// supplementTextView.setOnClickListener(null);
// if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
// PreferencesActivity.KEY_SUPPLEMENTAL, true)) {
// SupplementalInfoRetriever.maybeInvokeRetrieval(supplementTextView,
// resultHandler.getResult(),
// historyManager,
// this);
// }
//
// int buttonCount = resultHandler.getButtonCount();
// ViewGroup buttonView = (ViewGroup) findViewById(R.id.result_button_view);
// buttonView.requestFocus();
// for (int x = 0; x < ResultHandler.MAX_BUTTON_COUNT; x++) {
// TextView button = (TextView) buttonView.getChildAt(x);
// if (x < buttonCount) {
// button.setVisibility(View.VISIBLE);
// button.setText(resultHandler.getButtonText(x));
// button.setOnClickListener(new ResultButtonListener(resultHandler, x));
// } else {
// button.setVisibility(View.GONE);
// }
// }
//
// }
//
// // Briefly show the contents of the barcode, then handle the result outside Barcode Scanner.
// private void handleDecodeExternally(Result rawResult, ResultHandler resultHandler, Bitmap barcode) {
//
// if (barcode != null) {
// viewfinderView.drawResultBitmap(barcode);
// }
//
// long resultDurationMS;
// if (getIntent() == null) {
// resultDurationMS = DEFAULT_INTENT_RESULT_DURATION_MS;
// } else {
// resultDurationMS = getIntent().getLongExtra(Intents.Scan.RESULT_DISPLAY_DURATION_MS,
// DEFAULT_INTENT_RESULT_DURATION_MS);
// }
//
// if (resultDurationMS > 0) {
// String rawResultString = String.valueOf(rawResult);
// if (rawResultString.length() > 32) {
// rawResultString = rawResultString.substring(0, 32) + " ...";
// }
// statusView.setText(getString(resultHandler.getDisplayTitle()) + " : " + rawResultString);
// }
//
// maybeSetClipboard(resultHandler);
//
// switch (source) {
// case NATIVE_APP_INTENT:
// // Hand back whatever action they requested - this can be changed to Intents.Scan.ACTION when
// // the deprecated intent is retired.
// Intent intent = new Intent(getIntent().getAction());
// intent.addFlags(Intents.FLAG_NEW_DOC);
// intent.putExtra(Intents.Scan.RESULT, rawResult.toString());
// intent.putExtra(Intents.Scan.RESULT_FORMAT, rawResult.getBarcodeFormat().toString());
// byte[] rawBytes = rawResult.getRawBytes();
// if (rawBytes != null && rawBytes.length > 0) {
// intent.putExtra(Intents.Scan.RESULT_BYTES, rawBytes);
// }
// Map<ResultMetadataType, ?> metadata = rawResult.getResultMetadata();
// if (metadata != null) {
// if (metadata.containsKey(ResultMetadataType.UPC_EAN_EXTENSION)) {
// intent.putExtra(Intents.Scan.RESULT_UPC_EAN_EXTENSION,
// metadata.get(ResultMetadataType.UPC_EAN_EXTENSION).toString());
// }
// Number orientation = (Number) metadata.get(ResultMetadataType.ORIENTATION);
// if (orientation != null) {
// intent.putExtra(Intents.Scan.RESULT_ORIENTATION, orientation.intValue());
// }
// String ecLevel = (String) metadata.get(ResultMetadataType.ERROR_CORRECTION_LEVEL);
// if (ecLevel != null) {
// intent.putExtra(Intents.Scan.RESULT_ERROR_CORRECTION_LEVEL, ecLevel);
// }
// @SuppressWarnings("unchecked")
// Iterable<byte[]> byteSegments = (Iterable<byte[]>) metadata.get(ResultMetadataType.BYTE_SEGMENTS);
// if (byteSegments != null) {
// int i = 0;
// for (byte[] byteSegment : byteSegments) {
// intent.putExtra(Intents.Scan.RESULT_BYTE_SEGMENTS_PREFIX + i, byteSegment);
// i++;
// }
// }
// }
// sendReplyMessage(R.id.return_scan_result, intent, resultDurationMS);
// break;
//
// case PRODUCT_SEARCH_LINK:
// // Reformulate the URL which triggered us into a query, so that the request goes to the same
// // TLD as the scan URL.
// int end = sourceUrl.lastIndexOf("/scan");
// String productReplyURL = sourceUrl.substring(0, end) + "?q=" +
// resultHandler.getDisplayContents() + "&source=zxing";
// sendReplyMessage(R.id.launch_product_query, productReplyURL, resultDurationMS);
// break;
//
// case ZXING_LINK:
// if (scanFromWebPageManager != null && scanFromWebPageManager.isScanFromWebPage()) {
// String linkReplyURL = scanFromWebPageManager.buildReplyURL(rawResult, resultHandler);
// scanFromWebPageManager = null;
// sendReplyMessage(R.id.launch_product_query, linkReplyURL, resultDurationMS);
// }
// break;
// }
// }
//
// private void maybeSetClipboard(ResultHandler resultHandler) {
// if (copyToClipboard && !resultHandler.areContentsSecure()) {
// ClipboardInterface.setText(resultHandler.getDisplayContents(), this);
// }
// }
private void sendReplyMessage(int id, Object arg, long delayMS) {
if (handler != null) {
Message message = Message.obtain(handler, id, arg);
if (delayMS > 0L) {
handler.sendMessageDelayed(message, delayMS);
} else {
handler.sendMessage(message);
}
}
}
private void initCamera(SurfaceHolder surfaceHolder) {
if (surfaceHolder == null) {
throw new IllegalStateException("No SurfaceHolder provided");
}
if (cameraManager.isOpen()) {
Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?");
return;
}
try {
cameraManager.openDriver(surfaceHolder);
// Creating the handler starts the preview, which can also throw a RuntimeException.
if (handler == null) {
handler = new CaptureActivityHandler(this, decodeFormats, decodeHints, characterSet, cameraManager);
}
decodeOrStoreSavedBitmap(null, null);
} catch (IOException ioe) {
Log.w(TAG, ioe);
// displayFrameworkBugMessageAndExit();
} catch (RuntimeException e) {
// Barcode Scanner has seen crashes in the wild of this variety:
// java.?lang.?RuntimeException: Fail to connect to camera service
Log.w(TAG, "Unexpected error initializing camera", e);
// displayFrameworkBugMessageAndExit();
}
}
// private void displayFrameworkBugMessageAndExit() {
// AlertDialog.Builder builder = new AlertDialog.Builder(this);
// builder.setTitle(getString(R.string.app_name));
// builder.setMessage(getString(R.string.msg_camera_framework_bug));
// builder.setPositiveButton(R.string.button_ok, new FinishListener(this));
// builder.setOnCancelListener(new FinishListener(this));
// builder.show();
// }
public void restartPreviewAfterDelay(long delayMS) {
if (handler != null) {
handler.sendEmptyMessageDelayed(R.id.restart_preview, delayMS);
}
resetStatusView();
}
private void resetStatusView() {
// resultView.setVisibility(View.GONE);
// statusView.setText(R.string.msg_default_status);
// statusView.setVisibility(View.VISIBLE);
viewfinderView.setVisibility(View.VISIBLE);
lastResult = null;
}
public void drawViewfinder() {
viewfinderView.drawViewfinder();
}
}

View File

@@ -0,0 +1,169 @@
package com.king.zxing;
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.ActivityNotFoundException;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.BitmapFactory;
import android.provider.Browser;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.Result;
import com.king.zxing.camera.CameraManager;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.util.Collection;
import java.util.Map;
/**
* This class handles all the messaging which comprises the state machine for capture.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class CaptureActivityHandler extends Handler {
private static final String TAG = CaptureActivityHandler.class.getSimpleName();
private final CaptureActivity activity;
private final DecodeThread decodeThread;
private State state;
private final CameraManager cameraManager;
private enum State {
PREVIEW,
SUCCESS,
DONE
}
CaptureActivityHandler(CaptureActivity activity,
Collection<BarcodeFormat> decodeFormats,
Map<DecodeHintType,?> baseHints,
String characterSet,
CameraManager cameraManager) {
this.activity = activity;
decodeThread = new DecodeThread(activity, decodeFormats, baseHints, characterSet,
new ViewfinderResultPointCallback(activity.getViewfinderView()));
decodeThread.start();
state = State.SUCCESS;
// Start ourselves capturing previews and decoding.
this.cameraManager = cameraManager;
cameraManager.startPreview();
restartPreviewAndDecode();
}
@Override
public void handleMessage(Message message) {
if (message.what == R.id.restart_preview) {
restartPreviewAndDecode();
} else if (message.what == R.id.decode_succeeded) {
state = State.SUCCESS;
Bundle bundle = message.getData();
Bitmap barcode = null;
float scaleFactor = 1.0f;
if (bundle != null) {
byte[] compressedBitmap = bundle.getByteArray(DecodeThread.BARCODE_BITMAP);
if (compressedBitmap != null) {
barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null);
// Mutable copy:
barcode = barcode.copy(Bitmap.Config.ARGB_8888, true);
}
scaleFactor = bundle.getFloat(DecodeThread.BARCODE_SCALED_FACTOR);
}
activity.handleDecode((Result) message.obj, barcode, scaleFactor);
} else if (message.what == R.id.decode_failed) {// We're decoding as fast as possible, so when one decode fails, start another.
state = State.PREVIEW;
cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
} else if (message.what == R.id.return_scan_result) {
activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
activity.finish();
} else if (message.what == R.id.launch_product_query) {
String url = (String) message.obj;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intents.FLAG_NEW_DOC);
intent.setData(Uri.parse(url));
ResolveInfo resolveInfo =
activity.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
String browserPackageName = null;
if (resolveInfo != null && resolveInfo.activityInfo != null) {
browserPackageName = resolveInfo.activityInfo.packageName;
Log.d(TAG, "Using browser in package " + browserPackageName);
}
// Needed for default Android browser / Chrome only apparently
if (browserPackageName != null) {
switch (browserPackageName) {
case "com.android.browser":
case "com.android.chrome":
intent.setPackage(browserPackageName);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, browserPackageName);
break;
}
}
try {
activity.startActivity(intent);
} catch (ActivityNotFoundException ignored) {
Log.w(TAG, "Can't find anything to handle VIEW of URI " + url);
}
}
}
public void quitSynchronously() {
state = State.DONE;
cameraManager.stopPreview();
Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit);
quit.sendToTarget();
try {
// Wait at most half a second; should be enough time, and onPause() will timeout quickly
decodeThread.join(500L);
} catch (InterruptedException e) {
// continue
}
// Be absolutely sure we don't send any queued up messages
removeMessages(R.id.decode_succeeded);
removeMessages(R.id.decode_failed);
}
private void restartPreviewAndDecode() {
if (state == State.SUCCESS) {
state = State.PREVIEW;
cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
activity.drawViewfinder();
}
}
}

View File

@@ -0,0 +1,105 @@
package com.king.zxing;
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Intent;
import android.net.Uri;
import com.google.zxing.BarcodeFormat;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
final class DecodeFormatManager {
private static final Pattern COMMA_PATTERN = Pattern.compile(",");
static final Set<BarcodeFormat> PRODUCT_FORMATS;
static final Set<BarcodeFormat> INDUSTRIAL_FORMATS;
private static final Set<BarcodeFormat> ONE_D_FORMATS;
static final Set<BarcodeFormat> QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE);
static final Set<BarcodeFormat> DATA_MATRIX_FORMATS = EnumSet.of(BarcodeFormat.DATA_MATRIX);
static final Set<BarcodeFormat> AZTEC_FORMATS = EnumSet.of(BarcodeFormat.AZTEC);
static final Set<BarcodeFormat> PDF417_FORMATS = EnumSet.of(BarcodeFormat.PDF_417);
static {
PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A,
BarcodeFormat.UPC_E,
BarcodeFormat.EAN_13,
BarcodeFormat.EAN_8,
BarcodeFormat.RSS_14,
BarcodeFormat.RSS_EXPANDED);
INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39,
BarcodeFormat.CODE_93,
BarcodeFormat.CODE_128,
BarcodeFormat.ITF,
BarcodeFormat.CODABAR);
ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS);
ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS);
}
private static final Map<String,Set<BarcodeFormat>> FORMATS_FOR_MODE;
static {
FORMATS_FOR_MODE = new HashMap<>();
FORMATS_FOR_MODE.put(Intents.Scan.ONE_D_MODE, ONE_D_FORMATS);
FORMATS_FOR_MODE.put(Intents.Scan.PRODUCT_MODE, PRODUCT_FORMATS);
FORMATS_FOR_MODE.put(Intents.Scan.QR_CODE_MODE, QR_CODE_FORMATS);
FORMATS_FOR_MODE.put(Intents.Scan.DATA_MATRIX_MODE, DATA_MATRIX_FORMATS);
FORMATS_FOR_MODE.put(Intents.Scan.AZTEC_MODE, AZTEC_FORMATS);
FORMATS_FOR_MODE.put(Intents.Scan.PDF417_MODE, PDF417_FORMATS);
}
private DecodeFormatManager() {}
static Set<BarcodeFormat> parseDecodeFormats(Intent intent) {
Iterable<String> scanFormats = null;
CharSequence scanFormatsString = intent.getStringExtra(Intents.Scan.FORMATS);
if (scanFormatsString != null) {
scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString));
}
return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE));
}
static Set<BarcodeFormat> parseDecodeFormats(Uri inputUri) {
List<String> formats = inputUri.getQueryParameters(Intents.Scan.FORMATS);
if (formats != null && formats.size() == 1 && formats.get(0) != null) {
formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0)));
}
return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE));
}
private static Set<BarcodeFormat> parseDecodeFormats(Iterable<String> scanFormats, String decodeMode) {
if (scanFormats != null) {
Set<BarcodeFormat> formats = EnumSet.noneOf(BarcodeFormat.class);
try {
for (String format : scanFormats) {
formats.add(BarcodeFormat.valueOf(format));
}
return formats;
} catch (IllegalArgumentException iae) {
// ignore it then
}
}
if (decodeMode != null) {
return FORMATS_FOR_MODE.get(decodeMode);
}
return null;
}
}

View File

@@ -0,0 +1,120 @@
package com.king.zxing;
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.graphics.Bitmap;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.util.Map;
final class DecodeHandler extends Handler {
private static final String TAG = DecodeHandler.class.getSimpleName();
private final CaptureActivity activity;
private final MultiFormatReader multiFormatReader;
private boolean running = true;
DecodeHandler(CaptureActivity activity, Map<DecodeHintType,Object> hints) {
multiFormatReader = new MultiFormatReader();
multiFormatReader.setHints(hints);
this.activity = activity;
}
@Override
public void handleMessage(Message message) {
if (message == null || !running) {
return;
}
if (message.what == R.id.decode) {
decode((byte[]) message.obj, message.arg1, message.arg2);
} else if (message.what == R.id.quit) {
running = false;
Looper.myLooper().quit();
}
}
/**
* Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
* reuse the same reader objects from one decode to the next.
*
* @param data The YUV preview frame.
* @param width The width of the preview frame.
* @param height The height of the preview frame.
*/
private void decode(byte[] data, int width, int height) {
long start = System.currentTimeMillis();
Result rawResult = null;
PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, width, height);
if (source != null) {
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
rawResult = multiFormatReader.decodeWithState(bitmap);
} catch (ReaderException re) {
// continue
} finally {
multiFormatReader.reset();
}
}
Handler handler = activity.getHandler();
if (rawResult != null) {
// Don't log the barcode contents for security.
long end = System.currentTimeMillis();
Log.d(TAG, "Found barcode in " + (end - start) + " ms");
if (handler != null) {
Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult);
Bundle bundle = new Bundle();
bundleThumbnail(source, bundle);
message.setData(bundle);
message.sendToTarget();
}
} else {
if (handler != null) {
Message message = Message.obtain(handler, R.id.decode_failed);
message.sendToTarget();
}
}
}
private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) {
int[] pixels = source.renderThumbnail();
int width = source.getThumbnailWidth();
int height = source.getThumbnailHeight();
Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888);
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);
bundle.putByteArray(DecodeThread.BARCODE_BITMAP, out.toByteArray());
bundle.putFloat(DecodeThread.BARCODE_SCALED_FACTOR, (float) width / source.getWidth());
}
}

View File

@@ -0,0 +1,237 @@
package com.king.zxing;
/*
* Copyright (C) 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import com.google.zxing.DecodeHintType;
/**
* @author Lachezar Dobrev
*/
final class DecodeHintManager {
private static final String TAG = DecodeHintManager.class.getSimpleName();
// This pattern is used in decoding integer arrays.
private static final Pattern COMMA = Pattern.compile(",");
private DecodeHintManager() {}
/**
* <p>Split a query string into a list of name-value pairs.</p>
*
* <p>This is an alternative to the {@link Uri#getQueryParameterNames()} and
* {@link Uri#getQueryParameters(String)}, which are quirky and not suitable
* for exist-only Uri parameters.</p>
*
* <p>This method ignores multiple parameters with the same name and returns the
* first one only. This is technically incorrect, but should be acceptable due
* to the method of processing Hints: no multiple values for a hint.</p>
*
* @param query query to split
* @return name-value pairs
*/
private static Map<String,String> splitQuery(String query) {
Map<String,String> map = new HashMap<>();
int pos = 0;
while (pos < query.length()) {
if (query.charAt(pos) == '&') {
// Skip consecutive ampersand separators.
pos ++;
continue;
}
int amp = query.indexOf('&', pos);
int equ = query.indexOf('=', pos);
if (amp < 0) {
// This is the last element in the query, no more ampersand elements.
String name;
String text;
if (equ < 0) {
// No equal sign
name = query.substring(pos);
name = name.replace('+', ' '); // Preemptively decode +
name = Uri.decode(name);
text = "";
} else {
// Split name and text.
name = query.substring(pos, equ);
name = name.replace('+', ' '); // Preemptively decode +
name = Uri.decode(name);
text = query.substring(equ + 1);
text = text.replace('+', ' '); // Preemptively decode +
text = Uri.decode(text);
}
if (!map.containsKey(name)) {
map.put(name, text);
}
break;
}
if (equ < 0 || equ > amp) {
// No equal sign until the &: this is a simple parameter with no value.
String name = query.substring(pos, amp);
name = name.replace('+', ' '); // Preemptively decode +
name = Uri.decode(name);
if (!map.containsKey(name)) {
map.put(name, "");
}
pos = amp + 1;
continue;
}
String name = query.substring(pos, equ);
name = name.replace('+', ' '); // Preemptively decode +
name = Uri.decode(name);
String text = query.substring(equ + 1, amp);
text = text.replace('+', ' '); // Preemptively decode +
text = Uri.decode(text);
if (!map.containsKey(name)) {
map.put(name, text);
}
pos = amp + 1;
}
return map;
}
static Map<DecodeHintType,?> parseDecodeHints(Uri inputUri) {
String query = inputUri.getEncodedQuery();
if (query == null || query.isEmpty()) {
return null;
}
// Extract parameters
Map<String, String> parameters = splitQuery(query);
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
for (DecodeHintType hintType: DecodeHintType.values()) {
if (hintType == DecodeHintType.CHARACTER_SET ||
hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
hintType == DecodeHintType.POSSIBLE_FORMATS) {
continue; // This hint is specified in another way
}
String parameterName = hintType.name();
String parameterText = parameters.get(parameterName);
if (parameterText == null) {
continue;
}
if (hintType.getValueType().equals(Object.class)) {
// This is an unspecified type of hint content. Use the value as is.
// TODO: Can we make a different assumption on this?
hints.put(hintType, parameterText);
continue;
}
if (hintType.getValueType().equals(Void.class)) {
// Void hints are just flags: use the constant specified by DecodeHintType
hints.put(hintType, Boolean.TRUE);
continue;
}
if (hintType.getValueType().equals(String.class)) {
// A string hint: use the decoded value.
hints.put(hintType, parameterText);
continue;
}
if (hintType.getValueType().equals(Boolean.class)) {
// A boolean hint: a few values for false, everything else is true.
// An empty parameter is simply a flag-style parameter, assuming true
if (parameterText.isEmpty()) {
hints.put(hintType, Boolean.TRUE);
} else if ("0".equals(parameterText) ||
"false".equalsIgnoreCase(parameterText) ||
"no".equalsIgnoreCase(parameterText)) {
hints.put(hintType, Boolean.FALSE);
} else {
hints.put(hintType, Boolean.TRUE);
}
continue;
}
if (hintType.getValueType().equals(int[].class)) {
// An integer array. Used to specify valid lengths.
// Strip a trailing comma as in Java style array initialisers.
if (!parameterText.isEmpty() && parameterText.charAt(parameterText.length() - 1) == ',') {
parameterText = parameterText.substring(0, parameterText.length() - 1);
}
String[] values = COMMA.split(parameterText);
int[] array = new int[values.length];
for (int i = 0; i < values.length; i++) {
try {
array[i] = Integer.parseInt(values[i]);
} catch (NumberFormatException ignored) {
Log.w(TAG, "Skipping array of integers hint " + hintType + " due to invalid numeric value: '" + values[i] + '\'');
array = null;
break;
}
}
if (array != null) {
hints.put(hintType, array);
}
continue;
}
Log.w(TAG, "Unsupported hint type '" + hintType + "' of type " + hintType.getValueType());
}
Log.i(TAG, "Hints from the URI: " + hints);
return hints;
}
static Map<DecodeHintType, Object> parseDecodeHints(Intent intent) {
Bundle extras = intent.getExtras();
if (extras == null || extras.isEmpty()) {
return null;
}
Map<DecodeHintType,Object> hints = new EnumMap<>(DecodeHintType.class);
for (DecodeHintType hintType: DecodeHintType.values()) {
if (hintType == DecodeHintType.CHARACTER_SET ||
hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
hintType == DecodeHintType.POSSIBLE_FORMATS) {
continue; // This hint is specified in another way
}
String hintName = hintType.name();
if (extras.containsKey(hintName)) {
if (hintType.getValueType().equals(Void.class)) {
// Void hints are just flags: use the constant specified by the DecodeHintType
hints.put(hintType, Boolean.TRUE);
} else {
Object hintData = extras.get(hintName);
if (hintType.getValueType().isInstance(hintData)) {
hints.put(hintType, hintData);
} else {
Log.w(TAG, "Ignoring hint " + hintType + " because it is not assignable from " + hintData);
}
}
}
}
Log.i(TAG, "Hints from the Intent: " + hints);
return hints;
}
}

View File

@@ -0,0 +1,114 @@
package com.king.zxing;
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.ResultPointCallback;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.util.Log;
import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
/**
* This thread does all the heavy lifting of decoding the images.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
final class DecodeThread extends Thread {
public static final String BARCODE_BITMAP = "barcode_bitmap";
public static final String BARCODE_SCALED_FACTOR = "barcode_scaled_factor";
private final CaptureActivity activity;
private final Map<DecodeHintType,Object> hints;
private Handler handler;
private final CountDownLatch handlerInitLatch;
DecodeThread(CaptureActivity activity,
Collection<BarcodeFormat> decodeFormats,
Map<DecodeHintType,?> baseHints,
String characterSet,
ResultPointCallback resultPointCallback) {
this.activity = activity;
handlerInitLatch = new CountDownLatch(1);
hints = new EnumMap<>(DecodeHintType.class);
if (baseHints != null) {
hints.putAll(baseHints);
}
// The prefs can't change while the thread is running, so pick them up once here.
if (decodeFormats == null || decodeFormats.isEmpty()) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
decodeFormats = EnumSet.noneOf(BarcodeFormat.class);
if (prefs.getBoolean(Preferences.KEY_DECODE_1D_PRODUCT, true)) {
decodeFormats.addAll(DecodeFormatManager.PRODUCT_FORMATS);
}
if (prefs.getBoolean(Preferences.KEY_DECODE_1D_INDUSTRIAL, true)) {
decodeFormats.addAll(DecodeFormatManager.INDUSTRIAL_FORMATS);
}
if (prefs.getBoolean(Preferences.KEY_DECODE_QR, true)) {
decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
}
if (prefs.getBoolean(Preferences.KEY_DECODE_DATA_MATRIX, true)) {
decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
}
if (prefs.getBoolean(Preferences.KEY_DECODE_AZTEC, false)) {
decodeFormats.addAll(DecodeFormatManager.AZTEC_FORMATS);
}
if (prefs.getBoolean(Preferences.KEY_DECODE_PDF417, false)) {
decodeFormats.addAll(DecodeFormatManager.PDF417_FORMATS);
}
}
hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
if (characterSet != null) {
hints.put(DecodeHintType.CHARACTER_SET, characterSet);
}
hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback);
Log.i("DecodeThread", "Hints: " + hints);
}
Handler getHandler() {
try {
handlerInitLatch.await();
} catch (InterruptedException ie) {
// continue?
}
return handler;
}
@Override
public void run() {
Looper.prepare();
handler = new DecodeHandler(activity, hints);
handlerInitLatch.countDown();
Looper.loop();
}
}

View File

@@ -0,0 +1,123 @@
package com.king.zxing;
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.BatteryManager;
import android.util.Log;
import java.util.concurrent.RejectedExecutionException;
/**
* Finishes an activity after a period of inactivity if the device is on battery power.
*/
final class InactivityTimer {
private static final String TAG = InactivityTimer.class.getSimpleName();
private static final long INACTIVITY_DELAY_MS = 5 * 60 * 1000L;
private final Activity activity;
private final BroadcastReceiver powerStatusReceiver;
private boolean registered;
private AsyncTask<Object,Object,Object> inactivityTask;
InactivityTimer(Activity activity) {
this.activity = activity;
powerStatusReceiver = new PowerStatusReceiver();
registered = false;
onActivity();
}
synchronized void onActivity() {
cancel();
inactivityTask = new InactivityAsyncTask();
try {
inactivityTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} catch (RejectedExecutionException ree) {
Log.w(TAG, "Couldn't schedule inactivity task; ignoring");
}
}
synchronized void onPause() {
cancel();
if (registered) {
activity.unregisterReceiver(powerStatusReceiver);
registered = false;
} else {
Log.w(TAG, "PowerStatusReceiver was never registered?");
}
}
synchronized void onResume() {
if (registered) {
Log.w(TAG, "PowerStatusReceiver was already registered?");
} else {
activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
registered = true;
}
onActivity();
}
private synchronized void cancel() {
AsyncTask<?,?,?> task = inactivityTask;
if (task != null) {
task.cancel(true);
inactivityTask = null;
}
}
void shutdown() {
cancel();
}
private final class PowerStatusReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
// 0 indicates that we're on battery
boolean onBatteryNow = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) <= 0;
if (onBatteryNow) {
InactivityTimer.this.onActivity();
} else {
InactivityTimer.this.cancel();
}
}
}
}
private final class InactivityAsyncTask extends AsyncTask<Object,Object,Object> {
@Override
protected Object doInBackground(Object... objects) {
try {
Thread.sleep(INACTIVITY_DELAY_MS);
Log.i(TAG, "Finishing activity due to inactivity");
activity.finish();
} catch (InterruptedException e) {
// continue without killing
}
return null;
}
}
}

View File

@@ -0,0 +1,303 @@
package com.king.zxing;
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Intent;
/**
* This class provides the constants to use when sending an Intent to Barcode Scanner.
* These strings are effectively API and cannot be changed.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class Intents {
private Intents() {
}
/**
* Constants related to the {@link Scan#ACTION} Intent.
*/
public static final class Scan {
/**
* Send this intent to open the Barcodes app in scanning mode, find a barcode, and return
* the results.
*/
public static final String ACTION = "com.google.zxing.client.android.SCAN";
/**
* By default, sending this will decode all barcodes that we understand. However it
* may be useful to limit scanning to certain formats. Use
* {@link android.content.Intent#putExtra(String, String)} with one of the values below.
*
* Setting this is effectively shorthand for setting explicit formats with {@link #FORMATS}.
* It is overridden by that setting.
*/
public static final String MODE = "SCAN_MODE";
/**
* Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get
* prices, reviews, etc. for products.
*/
public static final String PRODUCT_MODE = "PRODUCT_MODE";
/**
* Decode only 1D barcodes.
*/
public static final String ONE_D_MODE = "ONE_D_MODE";
/**
* Decode only QR codes.
*/
public static final String QR_CODE_MODE = "QR_CODE_MODE";
/**
* Decode only Data Matrix codes.
*/
public static final String DATA_MATRIX_MODE = "DATA_MATRIX_MODE";
/**
* Decode only Aztec.
*/
public static final String AZTEC_MODE = "AZTEC_MODE";
/**
* Decode only PDF417.
*/
public static final String PDF417_MODE = "PDF417_MODE";
/**
* Comma-separated list of formats to scan for. The values must match the names of
* {@link com.google.zxing.BarcodeFormat}s, e.g. {@link com.google.zxing.BarcodeFormat#EAN_13}.
* Example: "EAN_13,EAN_8,QR_CODE". This overrides {@link #MODE}.
*/
public static final String FORMATS = "SCAN_FORMATS";
/**
* Optional parameter to specify the id of the camera from which to recognize barcodes.
* Overrides the default camera that would otherwise would have been selected.
* If provided, should be an int.
*/
public static final String CAMERA_ID = "SCAN_CAMERA_ID";
/**
* @see com.google.zxing.DecodeHintType#CHARACTER_SET
*/
public static final String CHARACTER_SET = "CHARACTER_SET";
/**
* Optional parameters to specify the width and height of the scanning rectangle in pixels.
* The app will try to honor these, but will clamp them to the size of the preview frame.
* You should specify both or neither, and pass the size as an int.
*/
public static final String WIDTH = "SCAN_WIDTH";
public static final String HEIGHT = "SCAN_HEIGHT";
/**
* Desired duration in milliseconds for which to pause after a successful scan before
* returning to the calling intent. Specified as a long, not an integer!
* For example: 1000L, not 1000.
*/
public static final String RESULT_DISPLAY_DURATION_MS = "RESULT_DISPLAY_DURATION_MS";
/**
* Prompt to show on-screen when scanning by intent. Specified as a {@link String}.
*/
public static final String PROMPT_MESSAGE = "PROMPT_MESSAGE";
/**
* If a barcode is found, Barcodes returns {@link android.app.Activity#RESULT_OK} to
* {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)}
* of the app which requested the scan via
* {@link android.app.Activity#startActivityForResult(android.content.Intent, int)}
* The barcodes contents can be retrieved with
* {@link android.content.Intent#getStringExtra(String)}.
* If the user presses Back, the result code will be {@link android.app.Activity#RESULT_CANCELED}.
*/
public static final String RESULT = "SCAN_RESULT";
/**
* Call {@link android.content.Intent#getStringExtra(String)} with {@code RESULT_FORMAT}
* to determine which barcode format was found.
* See {@link com.google.zxing.BarcodeFormat} for possible values.
*/
public static final String RESULT_FORMAT = "SCAN_RESULT_FORMAT";
/**
* Call {@link android.content.Intent#getStringExtra(String)} with {@code RESULT_UPC_EAN_EXTENSION}
* to return the content of any UPC extension barcode that was also found. Only applicable
* to {@link com.google.zxing.BarcodeFormat#UPC_A} and {@link com.google.zxing.BarcodeFormat#EAN_13}
* formats.
*/
public static final String RESULT_UPC_EAN_EXTENSION = "SCAN_RESULT_UPC_EAN_EXTENSION";
/**
* Call {@link android.content.Intent#getByteArrayExtra(String)} with {@code RESULT_BYTES}
* to get a {@code byte[]} of raw bytes in the barcode, if available.
*/
public static final String RESULT_BYTES = "SCAN_RESULT_BYTES";
/**
* Key for the value of {@link com.google.zxing.ResultMetadataType#ORIENTATION}, if available.
* Call {@link android.content.Intent#getIntArrayExtra(String)} with {@code RESULT_ORIENTATION}.
*/
public static final String RESULT_ORIENTATION = "SCAN_RESULT_ORIENTATION";
/**
* Key for the value of {@link com.google.zxing.ResultMetadataType#ERROR_CORRECTION_LEVEL}, if available.
* Call {@link android.content.Intent#getStringExtra(String)} with {@code RESULT_ERROR_CORRECTION_LEVEL}.
*/
public static final String RESULT_ERROR_CORRECTION_LEVEL = "SCAN_RESULT_ERROR_CORRECTION_LEVEL";
/**
* Prefix for keys that map to the values of {@link com.google.zxing.ResultMetadataType#BYTE_SEGMENTS},
* if available. The actual values will be set under a series of keys formed by adding 0, 1, 2, ...
* to this prefix. So the first byte segment is under key "SCAN_RESULT_BYTE_SEGMENTS_0" for example.
* Call {@link android.content.Intent#getByteArrayExtra(String)} with these keys.
*/
public static final String RESULT_BYTE_SEGMENTS_PREFIX = "SCAN_RESULT_BYTE_SEGMENTS_";
/**
* Setting this to false will not save scanned codes in the history. Specified as a {@code boolean}.
*/
public static final String SAVE_HISTORY = "SAVE_HISTORY";
private Scan() {
}
}
/**
* Constants related to the scan history and retrieving history items.
*/
public static final class History {
public static final String ITEM_NUMBER = "ITEM_NUMBER";
private History() {
}
}
/**
* Constants related to the {@link Encode#ACTION} Intent.
*/
public static final class Encode {
/**
* Send this intent to encode a piece of data as a QR code and display it full screen, so
* that another person can scan the barcode from your screen.
*/
public static final String ACTION = "com.google.zxing.client.android.ENCODE";
/**
* The data to encode. Use {@link android.content.Intent#putExtra(String, String)} or
* {@link android.content.Intent#putExtra(String, android.os.Bundle)},
* depending on the type and format specified. Non-QR Code formats should
* just use a String here. For QR Code, see Contents for details.
*/
public static final String DATA = "ENCODE_DATA";
/**
* The type of data being supplied if the format is QR Code. Use
* {@link android.content.Intent#putExtra(String, String)} with one of Contents.Type.
*/
public static final String TYPE = "ENCODE_TYPE";
/**
* The barcode format to be displayed. If this isn't specified or is blank,
* it defaults to QR Code. Use {@link android.content.Intent#putExtra(String, String)}, where
* format is one of {@link com.google.zxing.BarcodeFormat}.
*/
public static final String FORMAT = "ENCODE_FORMAT";
/**
* Normally the contents of the barcode are displayed to the user in a TextView. Setting this
* boolean to false will hide that TextView, showing only the encode barcode.
*/
public static final String SHOW_CONTENTS = "ENCODE_SHOW_CONTENTS";
private Encode() {
}
}
/**
* Constants related to the {@link SearchBookContents#ACTION} Intent.
*/
public static final class SearchBookContents {
/**
* Use Google Book Search to search the contents of the book provided.
*/
public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS";
/**
* The book to search, identified by ISBN number.
*/
public static final String ISBN = "ISBN";
/**
* An optional field which is the text to search for.
*/
public static final String QUERY = "QUERY";
private SearchBookContents() {
}
}
/**
* Constants related to the {@link WifiConnect#ACTION} Intent.
*/
public static final class WifiConnect {
/**
* Internal intent used to trigger connection to a wi-fi network.
*/
public static final String ACTION = "com.google.zxing.client.android.WIFI_CONNECT";
/**
* The network to connect to, all the configuration provided here.
*/
public static final String SSID = "SSID";
/**
* The network to connect to, all the configuration provided here.
*/
public static final String TYPE = "TYPE";
/**
* The network to connect to, all the configuration provided here.
*/
public static final String PASSWORD = "PASSWORD";
private WifiConnect() {
}
}
/**
* Constants related to the {@link Share#ACTION} Intent.
*/
public static final class Share {
/**
* Give the user a choice of items to encode as a barcode, then render it as a QR Code and
* display onscreen for a friend to scan with their phone.
*/
public static final String ACTION = "com.google.zxing.client.android.SHARE";
private Share() {
}
}
// Not the best place for this, but, better than a new class
// Should be FLAG_ACTIVITY_NEW_DOCUMENT in API 21+.
// Defined once here because the current value is deprecated, so generates just one warning
public static final int FLAG_NEW_DOC = Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET;
}

View File

@@ -0,0 +1,50 @@
package com.king.zxing;
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public final class Preferences {
public static final String KEY_DECODE_1D_PRODUCT = "preferences_decode_1D_product";
public static final String KEY_DECODE_1D_INDUSTRIAL = "preferences_decode_1D_industrial";
public static final String KEY_DECODE_QR = "preferences_decode_QR";
public static final String KEY_DECODE_DATA_MATRIX = "preferences_decode_Data_Matrix";
public static final String KEY_DECODE_AZTEC = "preferences_decode_Aztec";
public static final String KEY_DECODE_PDF417 = "preferences_decode_PDF417";
public static final String KEY_CUSTOM_PRODUCT_SEARCH = "preferences_custom_product_search";
public static final String KEY_PLAY_BEEP = "preferences_play_beep";
public static final String KEY_VIBRATE = "preferences_vibrate";
public static final String KEY_COPY_TO_CLIPBOARD = "preferences_copy_to_clipboard";
public static final String KEY_FRONT_LIGHT_MODE = "preferences_front_light_mode";
public static final String KEY_BULK_MODE = "preferences_bulk_mode";
public static final String KEY_REMEMBER_DUPLICATES = "preferences_remember_duplicates";
public static final String KEY_ENABLE_HISTORY = "preferences_history";
public static final String KEY_SUPPLEMENTAL = "preferences_supplemental";
public static final String KEY_AUTO_FOCUS = "preferences_auto_focus";
public static final String KEY_INVERT_SCAN = "preferences_invert_scan";
public static final String KEY_SEARCH_COUNTRY = "preferences_search_country";
public static final String KEY_DISABLE_AUTO_ORIENTATION = "preferences_orientation";
public static final String KEY_DISABLE_CONTINUOUS_FOCUS = "preferences_disable_continuous_focus";
public static final String KEY_DISABLE_EXPOSURE = "preferences_disable_exposure";
public static final String KEY_DISABLE_METERING = "preferences_disable_metering";
public static final String KEY_DISABLE_BARCODE_SCENE_MODE = "preferences_disable_barcode_scene_mode";
public static final String KEY_AUTO_OPEN_WEB = "preferences_auto_open_web";
}

View File

@@ -0,0 +1,36 @@
package com.king.zxing;
/*
* Copyright (C) 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import com.google.zxing.ResultPoint;
import com.google.zxing.ResultPointCallback;
final class ViewfinderResultPointCallback implements ResultPointCallback {
private final ViewfinderView viewfinderView;
ViewfinderResultPointCallback(ViewfinderView viewfinderView) {
this.viewfinderView = viewfinderView;
}
@Override
public void foundPossibleResultPoint(ResultPoint point) {
viewfinderView.addPossibleResultPoint(point);
}
}

View File

@@ -0,0 +1,345 @@
package com.king.zxing;
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.support.v4.content.ContextCompat;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.google.zxing.ResultPoint;
import com.king.zxing.camera.CameraManager;
import java.util.ArrayList;
import java.util.List;
/**
* This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
* transparency outside it, as well as the laser scanner animation and result points.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ViewfinderView extends View {
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
private static final long ANIMATION_DELAY = 20L;
private static final int CURRENT_POINT_OPACITY = 0xA0;
private static final int MAX_RESULT_POINTS = 20;
private static final int POINT_SIZE = 6;
private static final int CORNER_RECT_WIDTH = 8; //扫描区边角的宽
private static final int CORNER_RECT_HEIGHT = 40; //扫描区边角的高
private static final int SCANNER_LINE_MOVE_DISTANCE = 6; //扫描线移动距离
private static final int SCANNER_LINE_HEIGHT = 10; //扫描线宽度
private CameraManager cameraManager;
private final Paint paint;
private final TextPaint textPaint;
private Bitmap resultBitmap;
private final int maskColor;
// private final int resultColor;
//扫描区域边框颜色
private final int frameColor;
//扫描线颜色
private final int laserColor;
//四角颜色
private final int cornerColor;
private final int resultPointColor;
private int scannerAlpha;
private final float textPadding;
private TextLocation textLocation;
//扫描区域提示文本
private String labelText;
//扫描区域提示文本颜色
private final int labelTextColor;
private final float labelTextSize;
public static int scannerStart = 0;
public static int scannerEnd = 0;
private List<ResultPoint> possibleResultPoints;
private List<ResultPoint> lastPossibleResultPoints;
public enum TextLocation {
TOP(0),BOTTOM(1);
private int mValue;
TextLocation(int value){
mValue = value;
}
private static TextLocation getFromInt(int value){
for(TextLocation location : TextLocation.values()){
if(location.mValue == value){
return location;
}
}
return TextLocation.TOP;
}
}
// This constructor is used when the class is built from an XML resource.
public ViewfinderView(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化自定义属性信息
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ViewfinderView);
maskColor = array.getColor(R.styleable.ViewfinderView_maskColor, ContextCompat.getColor(context,R.color.viewfinder_mask));
frameColor = array.getColor(R.styleable.ViewfinderView_frameColor, ContextCompat.getColor(context,R.color.viewfinder_frame));
cornerColor = array.getColor(R.styleable.ViewfinderView_cornerColor, ContextCompat.getColor(context,R.color.viewfinder_corner));
laserColor = array.getColor(R.styleable.ViewfinderView_laserColor, ContextCompat.getColor(context,R.color.viewfinder_laser));
resultPointColor = array.getColor(R.styleable.ViewfinderView_resultPointColor, ContextCompat.getColor(context,R.color.viewfinder_result_point_color));
labelText = array.getString(R.styleable.ViewfinderView_text);
labelTextColor = array.getColor(R.styleable.ViewfinderView_textColor, ContextCompat.getColor(context,R.color.viewfinder_text_color));
labelTextSize = array.getDimension(R.styleable.ViewfinderView_textSize, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,14f,getResources().getDisplayMetrics()));
textPadding = array.getDimension(R.styleable.ViewfinderView_textPadding,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,24,getResources().getDisplayMetrics()));
textLocation = TextLocation.getFromInt(array.getInt(R.styleable.ViewfinderView_textLocation,0));
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
scannerAlpha = 0;
possibleResultPoints = new ArrayList<>(5);
lastPossibleResultPoints = null;
}
public void setCameraManager(CameraManager cameraManager) {
this.cameraManager = cameraManager;
}
@SuppressLint("DrawAllocation")
@Override
public void onDraw(Canvas canvas) {
if (cameraManager == null) {
return; // not ready yet, early draw before done configuring
}
Rect frame = cameraManager.getFramingRect();
Rect previewFrame = cameraManager.getFramingRectInPreview();
if (frame == null || previewFrame == null) {
return;
}
if(scannerStart == 0 || scannerEnd == 0) {
scannerStart = frame.top;
scannerEnd = frame.bottom - SCANNER_LINE_HEIGHT;
}
int width = canvas.getWidth();
int height = canvas.getHeight();
// Draw the exterior (i.e. outside the framing rect) darkened
drawExterior(canvas,frame,width,height);
if (resultBitmap != null) {
// Draw the opaque result bitmap over the scanning rectangle
paint.setAlpha(CURRENT_POINT_OPACITY);
canvas.drawBitmap(resultBitmap, null, frame, paint);
} else {
// Draw a red "laser scanner" line through the middle to show decoding is active
// paint.setColor(laserColor);
// paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
// scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
// Draw a two pixel solid black border inside the framing rect
drawFrame(canvas, frame);
// 绘制边角
drawCorner(canvas, frame);
// Draw a red "laser scanner" line through the middle to show decoding is active
drawLaserScanner(canvas,frame);
//绘制提示信息
drawTextInfo(canvas, frame);
float scaleX = frame.width() / (float) previewFrame.width();
float scaleY = frame.height() / (float) previewFrame.height();
List<ResultPoint> currentPossible = possibleResultPoints;
List<ResultPoint> currentLast = lastPossibleResultPoints;
int frameLeft = frame.left;
int frameTop = frame.top;
if (currentPossible.isEmpty()) {
lastPossibleResultPoints = null;
} else {
possibleResultPoints = new ArrayList<>(5);
lastPossibleResultPoints = currentPossible;
paint.setAlpha(CURRENT_POINT_OPACITY);
paint.setColor(resultPointColor);
synchronized (currentPossible) {
for (ResultPoint point : currentPossible) {
canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
POINT_SIZE, paint);
}
}
}
if (currentLast != null) {
paint.setAlpha(CURRENT_POINT_OPACITY / 2);
paint.setColor(resultPointColor);
synchronized (currentLast) {
float radius = POINT_SIZE / 2.0f;
for (ResultPoint point : currentLast) {
canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
radius, paint);
}
}
}
// Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask.
postInvalidateDelayed(ANIMATION_DELAY,
frame.left - POINT_SIZE,
frame.top - POINT_SIZE,
frame.right + POINT_SIZE,
frame.bottom + POINT_SIZE);
}
}
//绘制文本
private void drawTextInfo(Canvas canvas, Rect frame) {
if(!TextUtils.isEmpty(labelText)){
textPaint.setColor(labelTextColor);
textPaint.setTextSize(labelTextSize);
textPaint.setTextAlign(Paint.Align.CENTER);
StaticLayout staticLayout = new StaticLayout(labelText,textPaint,canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL,1.0f,0.0f,true);
if(textLocation == TextLocation.BOTTOM){
canvas.translate(frame.left + frame.width() / 2,frame.bottom + textPadding);
staticLayout.draw(canvas);
}else{
canvas.translate(frame.left + frame.width() / 2,frame.top - textPadding - staticLayout.getHeight());
staticLayout.draw(canvas);
}
}
}
//绘制边角
private void drawCorner(Canvas canvas, Rect frame) {
paint.setColor(cornerColor);
//左上
canvas.drawRect(frame.left, frame.top, frame.left + CORNER_RECT_WIDTH, frame.top + CORNER_RECT_HEIGHT, paint);
canvas.drawRect(frame.left, frame.top, frame.left + CORNER_RECT_HEIGHT, frame.top + CORNER_RECT_WIDTH, paint);
//右上
canvas.drawRect(frame.right - CORNER_RECT_WIDTH, frame.top, frame.right, frame.top + CORNER_RECT_HEIGHT, paint);
canvas.drawRect(frame.right - CORNER_RECT_HEIGHT, frame.top, frame.right, frame.top + CORNER_RECT_WIDTH, paint);
//左下
canvas.drawRect(frame.left, frame.bottom - CORNER_RECT_WIDTH, frame.left + CORNER_RECT_HEIGHT, frame.bottom, paint);
canvas.drawRect(frame.left, frame.bottom - CORNER_RECT_HEIGHT, frame.left + CORNER_RECT_WIDTH, frame.bottom, paint);
//右下
canvas.drawRect(frame.right - CORNER_RECT_WIDTH, frame.bottom - CORNER_RECT_HEIGHT, frame.right, frame.bottom, paint);
canvas.drawRect(frame.right - CORNER_RECT_HEIGHT, frame.bottom - CORNER_RECT_WIDTH, frame.right, frame.bottom, paint);
}
//绘制扫描线
private void drawLaserScanner(Canvas canvas, Rect frame) {
paint.setColor(laserColor);
//线性渐变
LinearGradient linearGradient = new LinearGradient(
frame.left, scannerStart,
frame.left, scannerStart + SCANNER_LINE_HEIGHT,
shadeColor(laserColor),
laserColor,
Shader.TileMode.MIRROR);
paint.setShader(linearGradient);
if(scannerStart <= scannerEnd) {
//椭圆
RectF rectF = new RectF(frame.left + 2 * SCANNER_LINE_HEIGHT, scannerStart, frame.right - 2 * SCANNER_LINE_HEIGHT, scannerStart + SCANNER_LINE_HEIGHT);
canvas.drawOval(rectF, paint);
scannerStart += SCANNER_LINE_MOVE_DISTANCE;
} else {
scannerStart = frame.top;
}
paint.setShader(null);
}
//处理颜色模糊
public int shadeColor(int color) {
String hax = Integer.toHexString(color);
String result = "20"+hax.substring(2);
return Integer.valueOf(result, 16);
}
// 绘制扫描区边框 Draw a two pixel solid black border inside the framing rect
private void drawFrame(Canvas canvas, Rect frame) {
paint.setColor(frameColor);
canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);
}
// 绘制模糊区域 Draw the exterior (i.e. outside the framing rect) darkened
private void drawExterior(Canvas canvas, Rect frame, int width, int height) {
paint.setColor(maskColor);
canvas.drawRect(0, 0, width, frame.top, paint);
canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
canvas.drawRect(0, frame.bottom + 1, width, height, paint);
}
public void drawViewfinder() {
Bitmap resultBitmap = this.resultBitmap;
this.resultBitmap = null;
if (resultBitmap != null) {
resultBitmap.recycle();
}
invalidate();
}
// /**
// * Draw a bitmap with the result points highlighted instead of the live scanning display.
// *
// * @param barcode An image of the decoded barcode.
// */
// public void drawResultBitmap(Bitmap barcode) {
// resultBitmap = barcode;
// invalidate();
// }
public void addPossibleResultPoint(ResultPoint point) {
List<ResultPoint> points = possibleResultPoints;
synchronized (points) {
points.add(point);
int size = points.size();
if (size > MAX_RESULT_POINTS) {
// trim it
points.subList(0, size - MAX_RESULT_POINTS / 2).clear();
}
}
}
}

View File

@@ -0,0 +1,132 @@
package com.king.zxing.camera;
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.content.SharedPreferences;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.RejectedExecutionException;
import com.king.zxing.Preferences;
@SuppressWarnings("deprecation") // camera APIs
final class AutoFocusManager implements Camera.AutoFocusCallback {
private static final String TAG = AutoFocusManager.class.getSimpleName();
private static final long AUTO_FOCUS_INTERVAL_MS = 1000L;
private static final Collection<String> FOCUS_MODES_CALLING_AF;
static {
FOCUS_MODES_CALLING_AF = new ArrayList<>(2);
FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO);
FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO);
}
private boolean stopped;
private boolean focusing;
private final boolean useAutoFocus;
private final Camera camera;
private AsyncTask<?,?,?> outstandingTask;
AutoFocusManager(Context context, Camera camera) {
this.camera = camera;
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
String currentFocusMode = camera.getParameters().getFocusMode();
useAutoFocus =
sharedPrefs.getBoolean(Preferences.KEY_AUTO_FOCUS, true) &&
FOCUS_MODES_CALLING_AF.contains(currentFocusMode);
Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus);
start();
}
@Override
public synchronized void onAutoFocus(boolean success, Camera theCamera) {
focusing = false;
autoFocusAgainLater();
}
private synchronized void autoFocusAgainLater() {
if (!stopped && outstandingTask == null) {
AutoFocusTask newTask = new AutoFocusTask();
try {
newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
outstandingTask = newTask;
} catch (RejectedExecutionException ree) {
Log.w(TAG, "Could not request auto focus", ree);
}
}
}
synchronized void start() {
if (useAutoFocus) {
outstandingTask = null;
if (!stopped && !focusing) {
try {
camera.autoFocus(this);
focusing = true;
} catch (RuntimeException re) {
// Have heard RuntimeException reported in Android 4.0.x+; continue?
Log.w(TAG, "Unexpected exception while focusing", re);
// Try again later to keep cycle going
autoFocusAgainLater();
}
}
}
}
private synchronized void cancelOutstandingTask() {
if (outstandingTask != null) {
if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) {
outstandingTask.cancel(true);
}
outstandingTask = null;
}
}
synchronized void stop() {
stopped = true;
if (useAutoFocus) {
cancelOutstandingTask();
// Doesn't hurt to call this even if not focusing
try {
camera.cancelAutoFocus();
} catch (RuntimeException re) {
// Have heard RuntimeException reported in Android 4.0.x+; continue?
Log.w(TAG, "Unexpected exception while cancelling focusing", re);
}
}
}
private final class AutoFocusTask extends AsyncTask<Object,Object,Object> {
@Override
protected Object doInBackground(Object... voids) {
try {
Thread.sleep(AUTO_FOCUS_INTERVAL_MS);
} catch (InterruptedException e) {
// continue
}
start();
return null;
}
}
}

View File

@@ -0,0 +1,257 @@
package com.king.zxing.camera;
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Point;
import android.hardware.Camera;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
import com.king.zxing.Preferences;
import com.king.zxing.camera.open.CameraFacing;
import com.king.zxing.camera.open.OpenCamera;
/**
* A class which deals with reading, parsing, and setting the camera parameters which are used to
* configure the camera hardware.
*/
@SuppressWarnings("deprecation") // camera APIs
final class CameraConfigurationManager {
private static final String TAG = "CameraConfiguration";
private final Context context;
private int cwNeededRotation;
private int cwRotationFromDisplayToCamera;
private Point screenResolution;
private Point cameraResolution;
private Point bestPreviewSize;
private Point previewSizeOnScreen;
CameraConfigurationManager(Context context) {
this.context = context;
}
/**
* Reads, one time, values from the camera that are needed by the app.
*/
void initFromCameraParameters(OpenCamera camera) {
Camera.Parameters parameters = camera.getCamera().getParameters();
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
int displayRotation = display.getRotation();
int cwRotationFromNaturalToDisplay;
switch (displayRotation) {
case Surface.ROTATION_0:
cwRotationFromNaturalToDisplay = 0;
break;
case Surface.ROTATION_90:
cwRotationFromNaturalToDisplay = 90;
break;
case Surface.ROTATION_180:
cwRotationFromNaturalToDisplay = 180;
break;
case Surface.ROTATION_270:
cwRotationFromNaturalToDisplay = 270;
break;
default:
// Have seen this return incorrect values like -90
if (displayRotation % 90 == 0) {
cwRotationFromNaturalToDisplay = (360 + displayRotation) % 360;
} else {
throw new IllegalArgumentException("Bad rotation: " + displayRotation);
}
}
Log.i(TAG, "Display at: " + cwRotationFromNaturalToDisplay);
int cwRotationFromNaturalToCamera = camera.getOrientation();
Log.i(TAG, "Camera at: " + cwRotationFromNaturalToCamera);
// Still not 100% sure about this. But acts like we need to flip this:
if (camera.getFacing() == CameraFacing.FRONT) {
cwRotationFromNaturalToCamera = (360 - cwRotationFromNaturalToCamera) % 360;
Log.i(TAG, "Front camera overriden to: " + cwRotationFromNaturalToCamera);
}
/*
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String overrideRotationString;
if (camera.getFacing() == CameraFacing.FRONT) {
overrideRotationString = prefs.getString(PreferencesActivity.KEY_FORCE_CAMERA_ORIENTATION_FRONT, null);
} else {
overrideRotationString = prefs.getString(PreferencesActivity.KEY_FORCE_CAMERA_ORIENTATION, null);
}
if (overrideRotationString != null && !"-".equals(overrideRotationString)) {
Log.i(TAG, "Overriding camera manually to " + overrideRotationString);
cwRotationFromNaturalToCamera = Integer.parseInt(overrideRotationString);
}
*/
cwRotationFromDisplayToCamera =
(360 + cwRotationFromNaturalToCamera - cwRotationFromNaturalToDisplay) % 360;
Log.i(TAG, "Final display orientation: " + cwRotationFromDisplayToCamera);
if (camera.getFacing() == CameraFacing.FRONT) {
Log.i(TAG, "Compensating rotation for front camera");
cwNeededRotation = (360 - cwRotationFromDisplayToCamera) % 360;
} else {
cwNeededRotation = cwRotationFromDisplayToCamera;
}
Log.i(TAG, "Clockwise rotation from display to camera: " + cwNeededRotation);
Point theScreenResolution = new Point();
display.getSize(theScreenResolution);
screenResolution = theScreenResolution;
Log.i(TAG, "Screen resolution in current orientation: " + screenResolution);
cameraResolution = CameraConfigurationUtils.findBestPreviewSizeValue(parameters, screenResolution);
Log.i(TAG, "Camera resolution: " + cameraResolution);
bestPreviewSize = CameraConfigurationUtils.findBestPreviewSizeValue(parameters, screenResolution);
Log.i(TAG, "Best available preview size: " + bestPreviewSize);
boolean isScreenPortrait = screenResolution.x < screenResolution.y;
boolean isPreviewSizePortrait = bestPreviewSize.x < bestPreviewSize.y;
if (isScreenPortrait == isPreviewSizePortrait) {
previewSizeOnScreen = bestPreviewSize;
} else {
previewSizeOnScreen = new Point(bestPreviewSize.y, bestPreviewSize.x);
}
Log.i(TAG, "Preview size on screen: " + previewSizeOnScreen);
}
void setDesiredCameraParameters(OpenCamera camera, boolean safeMode) {
Camera theCamera = camera.getCamera();
Camera.Parameters parameters = theCamera.getParameters();
if (parameters == null) {
Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration.");
return;
}
Log.i(TAG, "Initial camera parameters: " + parameters.flatten());
if (safeMode) {
Log.w(TAG, "In camera config safe mode -- most settings will not be honored");
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
initializeTorch(parameters, prefs, safeMode);
CameraConfigurationUtils.setFocus(
parameters,
prefs.getBoolean(Preferences.KEY_AUTO_FOCUS, true),
prefs.getBoolean(Preferences.KEY_DISABLE_CONTINUOUS_FOCUS, true),
safeMode);
if (!safeMode) {
if (prefs.getBoolean(Preferences.KEY_INVERT_SCAN, false)) {
CameraConfigurationUtils.setInvertColor(parameters);
}
if (!prefs.getBoolean(Preferences.KEY_DISABLE_BARCODE_SCENE_MODE, true)) {
CameraConfigurationUtils.setBarcodeSceneMode(parameters);
}
if (!prefs.getBoolean(Preferences.KEY_DISABLE_METERING, true)) {
CameraConfigurationUtils.setVideoStabilization(parameters);
CameraConfigurationUtils.setFocusArea(parameters);
CameraConfigurationUtils.setMetering(parameters);
}
//SetRecordingHint to true also a workaround for low framerate on Nexus 4
//https://stackoverflow.com/questions/14131900/extreme-camera-lag-on-nexus-4
parameters.setRecordingHint(true);
}
parameters.setPreviewSize(bestPreviewSize.x, bestPreviewSize.y);
theCamera.setParameters(parameters);
theCamera.setDisplayOrientation(cwRotationFromDisplayToCamera);
Camera.Parameters afterParameters = theCamera.getParameters();
Camera.Size afterSize = afterParameters.getPreviewSize();
if (afterSize != null && (bestPreviewSize.x != afterSize.width || bestPreviewSize.y != afterSize.height)) {
Log.w(TAG, "Camera said it supported preview size " + bestPreviewSize.x + 'x' + bestPreviewSize.y +
", but after setting it, preview size is " + afterSize.width + 'x' + afterSize.height);
bestPreviewSize.x = afterSize.width;
bestPreviewSize.y = afterSize.height;
}
}
Point getBestPreviewSize() {
return bestPreviewSize;
}
Point getPreviewSizeOnScreen() {
return previewSizeOnScreen;
}
Point getCameraResolution() {
return cameraResolution;
}
Point getScreenResolution() {
return screenResolution;
}
int getCWNeededRotation() {
return cwNeededRotation;
}
boolean getTorchState(Camera camera) {
if (camera != null) {
Camera.Parameters parameters = camera.getParameters();
if (parameters != null) {
String flashMode = parameters.getFlashMode();
return
Camera.Parameters.FLASH_MODE_ON.equals(flashMode) ||
Camera.Parameters.FLASH_MODE_TORCH.equals(flashMode);
}
}
return false;
}
void setTorch(Camera camera, boolean newSetting) {
Camera.Parameters parameters = camera.getParameters();
doSetTorch(parameters, newSetting, false);
camera.setParameters(parameters);
}
private void initializeTorch(Camera.Parameters parameters, SharedPreferences prefs, boolean safeMode) {
boolean currentSetting = FrontLightMode.readPref(prefs) == FrontLightMode.ON;
doSetTorch(parameters, currentSetting, safeMode);
}
private void doSetTorch(Camera.Parameters parameters, boolean newSetting, boolean safeMode) {
CameraConfigurationUtils.setTorch(parameters, newSetting);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (!safeMode && !prefs.getBoolean(Preferences.KEY_DISABLE_EXPOSURE, true)) {
CameraConfigurationUtils.setBestExposure(parameters, newSetting);
}
}
}

View File

@@ -0,0 +1,430 @@
package com.king.zxing.camera;
/*
* Copyright (C) 2014 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Build;
import android.util.Log;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
/**
* Utility methods for configuring the Android camera.
*
* @author Sean Owen
*/
@SuppressWarnings("deprecation") // camera APIs
public final class CameraConfigurationUtils {
private static final String TAG = "CameraConfiguration";
private static final Pattern SEMICOLON = Pattern.compile(";");
private static final int MIN_PREVIEW_PIXELS = 480 * 320; // normal screen
private static final float MAX_EXPOSURE_COMPENSATION = 1.5f;
private static final float MIN_EXPOSURE_COMPENSATION = 0.0f;
private static final double MAX_ASPECT_DISTORTION = 0.15;
private static final int MIN_FPS = 10;
private static final int MAX_FPS = 20;
private static final int AREA_PER_1000 = 400;
private CameraConfigurationUtils() {
}
public static void setFocus(Camera.Parameters parameters,
boolean autoFocus,
boolean disableContinuous,
boolean safeMode) {
List<String> supportedFocusModes = parameters.getSupportedFocusModes();
String focusMode = null;
if (autoFocus) {
if (safeMode || disableContinuous) {
focusMode = findSettableValue("focus mode",
supportedFocusModes,
Camera.Parameters.FOCUS_MODE_AUTO);
} else {
focusMode = findSettableValue("focus mode",
supportedFocusModes,
Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
Camera.Parameters.FOCUS_MODE_AUTO);
}
}
// Maybe selected auto-focus but not available, so fall through here:
if (!safeMode && focusMode == null) {
focusMode = findSettableValue("focus mode",
supportedFocusModes,
Camera.Parameters.FOCUS_MODE_MACRO,
Camera.Parameters.FOCUS_MODE_EDOF);
}
if (focusMode != null) {
if (focusMode.equals(parameters.getFocusMode())) {
Log.i(TAG, "Focus mode already set to " + focusMode);
} else {
parameters.setFocusMode(focusMode);
}
}
}
public static void setTorch(Camera.Parameters parameters, boolean on) {
List<String> supportedFlashModes = parameters.getSupportedFlashModes();
String flashMode;
if (on) {
flashMode = findSettableValue("flash mode",
supportedFlashModes,
Camera.Parameters.FLASH_MODE_TORCH,
Camera.Parameters.FLASH_MODE_ON);
} else {
flashMode = findSettableValue("flash mode",
supportedFlashModes,
Camera.Parameters.FLASH_MODE_OFF);
}
if (flashMode != null) {
if (flashMode.equals(parameters.getFlashMode())) {
Log.i(TAG, "Flash mode already set to " + flashMode);
} else {
Log.i(TAG, "Setting flash mode to " + flashMode);
parameters.setFlashMode(flashMode);
}
}
}
public static void setBestExposure(Camera.Parameters parameters, boolean lightOn) {
int minExposure = parameters.getMinExposureCompensation();
int maxExposure = parameters.getMaxExposureCompensation();
float step = parameters.getExposureCompensationStep();
if ((minExposure != 0 || maxExposure != 0) && step > 0.0f) {
// Set low when light is on
float targetCompensation = lightOn ? MIN_EXPOSURE_COMPENSATION : MAX_EXPOSURE_COMPENSATION;
int compensationSteps = Math.round(targetCompensation / step);
float actualCompensation = step * compensationSteps;
// Clamp value:
compensationSteps = Math.max(Math.min(compensationSteps, maxExposure), minExposure);
if (parameters.getExposureCompensation() == compensationSteps) {
Log.i(TAG, "Exposure compensation already set to " + compensationSteps + " / " + actualCompensation);
} else {
Log.i(TAG, "Setting exposure compensation to " + compensationSteps + " / " + actualCompensation);
parameters.setExposureCompensation(compensationSteps);
}
} else {
Log.i(TAG, "Camera does not support exposure compensation");
}
}
public static void setBestPreviewFPS(Camera.Parameters parameters) {
setBestPreviewFPS(parameters, MIN_FPS, MAX_FPS);
}
public static void setBestPreviewFPS(Camera.Parameters parameters, int minFPS, int maxFPS) {
List<int[]> supportedPreviewFpsRanges = parameters.getSupportedPreviewFpsRange();
Log.i(TAG, "Supported FPS ranges: " + toString(supportedPreviewFpsRanges));
if (supportedPreviewFpsRanges != null && !supportedPreviewFpsRanges.isEmpty()) {
int[] suitableFPSRange = null;
for (int[] fpsRange : supportedPreviewFpsRanges) {
int thisMin = fpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX];
int thisMax = fpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX];
if (thisMin >= minFPS * 1000 && thisMax <= maxFPS * 1000) {
suitableFPSRange = fpsRange;
break;
}
}
if (suitableFPSRange == null) {
Log.i(TAG, "No suitable FPS range?");
} else {
int[] currentFpsRange = new int[2];
parameters.getPreviewFpsRange(currentFpsRange);
if (Arrays.equals(currentFpsRange, suitableFPSRange)) {
Log.i(TAG, "FPS range already set to " + Arrays.toString(suitableFPSRange));
} else {
Log.i(TAG, "Setting FPS range to " + Arrays.toString(suitableFPSRange));
parameters.setPreviewFpsRange(suitableFPSRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
suitableFPSRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
}
}
}
}
public static void setFocusArea(Camera.Parameters parameters) {
if (parameters.getMaxNumFocusAreas() > 0) {
Log.i(TAG, "Old focus areas: " + toString(parameters.getFocusAreas()));
List<Camera.Area> middleArea = buildMiddleArea(AREA_PER_1000);
Log.i(TAG, "Setting focus area to : " + toString(middleArea));
parameters.setFocusAreas(middleArea);
} else {
Log.i(TAG, "Device does not support focus areas");
}
}
public static void setMetering(Camera.Parameters parameters) {
if (parameters.getMaxNumMeteringAreas() > 0) {
Log.i(TAG, "Old metering areas: " + parameters.getMeteringAreas());
List<Camera.Area> middleArea = buildMiddleArea(AREA_PER_1000);
Log.i(TAG, "Setting metering area to : " + toString(middleArea));
parameters.setMeteringAreas(middleArea);
} else {
Log.i(TAG, "Device does not support metering areas");
}
}
private static List<Camera.Area> buildMiddleArea(int areaPer1000) {
return Collections.singletonList(
new Camera.Area(new Rect(-areaPer1000, -areaPer1000, areaPer1000, areaPer1000), 1));
}
public static void setVideoStabilization(Camera.Parameters parameters) {
if (parameters.isVideoStabilizationSupported()) {
if (parameters.getVideoStabilization()) {
Log.i(TAG, "Video stabilization already enabled");
} else {
Log.i(TAG, "Enabling video stabilization...");
parameters.setVideoStabilization(true);
}
} else {
Log.i(TAG, "This device does not support video stabilization");
}
}
public static void setBarcodeSceneMode(Camera.Parameters parameters) {
if (Camera.Parameters.SCENE_MODE_BARCODE.equals(parameters.getSceneMode())) {
Log.i(TAG, "Barcode scene mode already set");
return;
}
String sceneMode = findSettableValue("scene mode",
parameters.getSupportedSceneModes(),
Camera.Parameters.SCENE_MODE_BARCODE);
if (sceneMode != null) {
parameters.setSceneMode(sceneMode);
}
}
public static void setZoom(Camera.Parameters parameters, double targetZoomRatio) {
if (parameters.isZoomSupported()) {
Integer zoom = indexOfClosestZoom(parameters, targetZoomRatio);
if (zoom == null) {
return;
}
if (parameters.getZoom() == zoom) {
Log.i(TAG, "Zoom is already set to " + zoom);
} else {
Log.i(TAG, "Setting zoom to " + zoom);
parameters.setZoom(zoom);
}
} else {
Log.i(TAG, "Zoom is not supported");
}
}
private static Integer indexOfClosestZoom(Camera.Parameters parameters, double targetZoomRatio) {
List<Integer> ratios = parameters.getZoomRatios();
Log.i(TAG, "Zoom ratios: " + ratios);
int maxZoom = parameters.getMaxZoom();
if (ratios == null || ratios.isEmpty() || ratios.size() != maxZoom + 1) {
Log.w(TAG, "Invalid zoom ratios!");
return null;
}
double target100 = 100.0 * targetZoomRatio;
double smallestDiff = Double.POSITIVE_INFINITY;
int closestIndex = 0;
for (int i = 0; i < ratios.size(); i++) {
double diff = Math.abs(ratios.get(i) - target100);
if (diff < smallestDiff) {
smallestDiff = diff;
closestIndex = i;
}
}
Log.i(TAG, "Chose zoom ratio of " + (ratios.get(closestIndex) / 100.0));
return closestIndex;
}
public static void setInvertColor(Camera.Parameters parameters) {
if (Camera.Parameters.EFFECT_NEGATIVE.equals(parameters.getColorEffect())) {
Log.i(TAG, "Negative effect already set");
return;
}
String colorMode = findSettableValue("color effect",
parameters.getSupportedColorEffects(),
Camera.Parameters.EFFECT_NEGATIVE);
if (colorMode != null) {
parameters.setColorEffect(colorMode);
}
}
public static Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) {
List<Camera.Size> rawSupportedSizes = parameters.getSupportedPreviewSizes();
if (rawSupportedSizes == null) {
Log.w(TAG, "Device returned no supported preview sizes; using default");
Camera.Size defaultSize = parameters.getPreviewSize();
if (defaultSize == null) {
throw new IllegalStateException("Parameters contained no preview size!");
}
return new Point(defaultSize.width, defaultSize.height);
}
if (Log.isLoggable(TAG, Log.INFO)) {
StringBuilder previewSizesString = new StringBuilder();
for (Camera.Size size : rawSupportedSizes) {
previewSizesString.append(size.width).append('x').append(size.height).append(' ');
}
Log.i(TAG, "Supported preview sizes: " + previewSizesString);
}
double screenAspectRatio = screenResolution.x / (double) screenResolution.y;
// Find a suitable size, with max resolution
int maxResolution = 0;
Camera.Size maxResPreviewSize = null;
for (Camera.Size size : rawSupportedSizes) {
int realWidth = size.width;
int realHeight = size.height;
int resolution = realWidth * realHeight;
if (resolution < MIN_PREVIEW_PIXELS) {
continue;
}
boolean isCandidatePortrait = realWidth < realHeight;
int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth;
int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight;
double aspectRatio = maybeFlippedWidth / (double) maybeFlippedHeight;
double distortion = Math.abs(aspectRatio - screenAspectRatio);
if (distortion > MAX_ASPECT_DISTORTION) {
continue;
}
if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) {
Point exactPoint = new Point(realWidth, realHeight);
Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint);
return exactPoint;
}
// Resolution is suitable; record the one with max resolution
if (resolution > maxResolution) {
maxResolution = resolution;
maxResPreviewSize = size;
}
}
// If no exact match, use largest preview size. This was not a great idea on older devices because
// of the additional computation needed. We're likely to get here on newer Android 4+ devices, where
// the CPU is much more powerful.
if (maxResPreviewSize != null) {
Point largestSize = new Point(maxResPreviewSize.width, maxResPreviewSize.height);
Log.i(TAG, "Using largest suitable preview size: " + largestSize);
return largestSize;
}
// If there is nothing at all suitable, return current preview size
Camera.Size defaultPreview = parameters.getPreviewSize();
if (defaultPreview == null) {
throw new IllegalStateException("Parameters contained no preview size!");
}
Point defaultSize = new Point(defaultPreview.width, defaultPreview.height);
Log.i(TAG, "No suitable preview sizes, using default: " + defaultSize);
return defaultSize;
}
private static String findSettableValue(String name,
Collection<String> supportedValues,
String... desiredValues) {
Log.i(TAG, "Requesting " + name + " value from among: " + Arrays.toString(desiredValues));
Log.i(TAG, "Supported " + name + " values: " + supportedValues);
if (supportedValues != null) {
for (String desiredValue : desiredValues) {
if (supportedValues.contains(desiredValue)) {
Log.i(TAG, "Can set " + name + " to: " + desiredValue);
return desiredValue;
}
}
}
Log.i(TAG, "No supported values match");
return null;
}
private static String toString(Collection<int[]> arrays) {
if (arrays == null || arrays.isEmpty()) {
return "[]";
}
StringBuilder buffer = new StringBuilder();
buffer.append('[');
Iterator<int[]> it = arrays.iterator();
while (it.hasNext()) {
buffer.append(Arrays.toString(it.next()));
if (it.hasNext()) {
buffer.append(", ");
}
}
buffer.append(']');
return buffer.toString();
}
private static String toString(Iterable<Camera.Area> areas) {
if (areas == null) {
return null;
}
StringBuilder result = new StringBuilder();
for (Camera.Area area : areas) {
result.append(area.rect).append(':').append(area.weight).append(' ');
}
return result.toString();
}
public static String collectStats(Camera.Parameters parameters) {
return collectStats(parameters.flatten());
}
public static String collectStats(CharSequence flattenedParams) {
StringBuilder result = new StringBuilder(1000);
result.append("BOARD=").append(Build.BOARD).append('\n');
result.append("BRAND=").append(Build.BRAND).append('\n');
result.append("CPU_ABI=").append(Build.CPU_ABI).append('\n');
result.append("DEVICE=").append(Build.DEVICE).append('\n');
result.append("DISPLAY=").append(Build.DISPLAY).append('\n');
result.append("FINGERPRINT=").append(Build.FINGERPRINT).append('\n');
result.append("HOST=").append(Build.HOST).append('\n');
result.append("ID=").append(Build.ID).append('\n');
result.append("MANUFACTURER=").append(Build.MANUFACTURER).append('\n');
result.append("MODEL=").append(Build.MODEL).append('\n');
result.append("PRODUCT=").append(Build.PRODUCT).append('\n');
result.append("TAGS=").append(Build.TAGS).append('\n');
result.append("TIME=").append(Build.TIME).append('\n');
result.append("TYPE=").append(Build.TYPE).append('\n');
result.append("USER=").append(Build.USER).append('\n');
result.append("VERSION.CODENAME=").append(Build.VERSION.CODENAME).append('\n');
result.append("VERSION.INCREMENTAL=").append(Build.VERSION.INCREMENTAL).append('\n');
result.append("VERSION.RELEASE=").append(Build.VERSION.RELEASE).append('\n');
result.append("VERSION.SDK_INT=").append(Build.VERSION.SDK_INT).append('\n');
if (flattenedParams != null) {
String[] params = SEMICOLON.split(flattenedParams);
Arrays.sort(params);
for (String param : params) {
result.append(param).append('\n');
}
}
return result.toString();
}
}

View File

@@ -0,0 +1,336 @@
package com.king.zxing.camera;
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Handler;
import android.util.Log;
import android.view.SurfaceHolder;
import com.google.zxing.PlanarYUVLuminanceSource;
import com.king.zxing.camera.open.OpenCamera;
import com.king.zxing.camera.open.OpenCameraInterface;
import java.io.IOException;
/**
* This object wraps the Camera service object and expects to be the only one talking to it. The
* implementation encapsulates the steps needed to take preview-sized images, which are used for
* both preview and decoding.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
@SuppressWarnings("deprecation") // camera APIs
public final class CameraManager {
private static final String TAG = CameraManager.class.getSimpleName();
private static final int MIN_FRAME_WIDTH = 240;
private static final int MIN_FRAME_HEIGHT = 240;
private static final int MAX_FRAME_WIDTH = 1200; // = 5/8 * 1920
private static final int MAX_FRAME_HEIGHT = 675; // = 5/8 * 1080
private final Context context;
private final CameraConfigurationManager configManager;
private OpenCamera camera;
private AutoFocusManager autoFocusManager;
private Rect framingRect;
private Rect framingRectInPreview;
private boolean initialized;
private boolean previewing;
private int requestedCameraId = OpenCameraInterface.NO_REQUESTED_CAMERA;
private int requestedFramingRectWidth;
private int requestedFramingRectHeight;
/**
* Preview frames are delivered here, which we pass on to the registered handler. Make sure to
* clear the handler so it will only receive one message.
*/
private final PreviewCallback previewCallback;
public CameraManager(Context context) {
this.context = context;
this.configManager = new CameraConfigurationManager(context);
previewCallback = new PreviewCallback(configManager);
}
/**
* Opens the camera driver and initializes the hardware parameters.
*
* @param holder The surface object which the camera will draw preview frames into.
* @throws IOException Indicates the camera driver failed to open.
*/
public synchronized void openDriver(SurfaceHolder holder) throws IOException {
OpenCamera theCamera = camera;
if (theCamera == null) {
theCamera = OpenCameraInterface.open(requestedCameraId);
if (theCamera == null) {
throw new IOException("Camera.open() failed to return object from driver");
}
camera = theCamera;
}
if (!initialized) {
initialized = true;
configManager.initFromCameraParameters(theCamera);
if (requestedFramingRectWidth > 0 && requestedFramingRectHeight > 0) {
setManualFramingRect(requestedFramingRectWidth, requestedFramingRectHeight);
requestedFramingRectWidth = 0;
requestedFramingRectHeight = 0;
}
}
Camera cameraObject = theCamera.getCamera();
Camera.Parameters parameters = cameraObject.getParameters();
String parametersFlattened = parameters == null ? null : parameters.flatten(); // Save these, temporarily
try {
configManager.setDesiredCameraParameters(theCamera, false);
} catch (RuntimeException re) {
// Driver failed
Log.w(TAG, "Camera rejected parameters. Setting only minimal safe-mode parameters");
Log.i(TAG, "Resetting to saved camera params: " + parametersFlattened);
// Reset:
if (parametersFlattened != null) {
parameters = cameraObject.getParameters();
parameters.unflatten(parametersFlattened);
try {
cameraObject.setParameters(parameters);
configManager.setDesiredCameraParameters(theCamera, true);
} catch (RuntimeException re2) {
// Well, darn. Give up
Log.w(TAG, "Camera rejected even safe-mode parameters! No configuration");
}
}
}
cameraObject.setPreviewDisplay(holder);
}
public synchronized boolean isOpen() {
return camera != null;
}
public OpenCamera getOpenCamera() {
return camera;
}
/**
* Closes the camera driver if still in use.
*/
public synchronized void closeDriver() {
if (camera != null) {
camera.getCamera().release();
camera = null;
// Make sure to clear these each time we close the camera, so that any scanning rect
// requested by intent is forgotten.
framingRect = null;
framingRectInPreview = null;
}
}
/**
* Asks the camera hardware to begin drawing preview frames to the screen.
*/
public synchronized void startPreview() {
OpenCamera theCamera = camera;
if (theCamera != null && !previewing) {
theCamera.getCamera().startPreview();
previewing = true;
autoFocusManager = new AutoFocusManager(context, theCamera.getCamera());
}
}
/**
* Tells the camera to stop drawing preview frames.
*/
public synchronized void stopPreview() {
if (autoFocusManager != null) {
autoFocusManager.stop();
autoFocusManager = null;
}
if (camera != null && previewing) {
camera.getCamera().stopPreview();
previewCallback.setHandler(null, 0);
previewing = false;
}
}
/**
* Convenience method for {@link com.king.zxing.CaptureActivity}
*
* @param newSetting if {@code true}, light should be turned on if currently off. And vice versa.
*/
public synchronized void setTorch(boolean newSetting) {
OpenCamera theCamera = camera;
if (theCamera != null && newSetting != configManager.getTorchState(theCamera.getCamera())) {
boolean wasAutoFocusManager = autoFocusManager != null;
if (wasAutoFocusManager) {
autoFocusManager.stop();
autoFocusManager = null;
}
configManager.setTorch(theCamera.getCamera(), newSetting);
if (wasAutoFocusManager) {
autoFocusManager = new AutoFocusManager(context, theCamera.getCamera());
autoFocusManager.start();
}
}
}
/**
* A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
* in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
* respectively.
*
* @param handler The handler to send the message to.
* @param message The what field of the message to be sent.
*/
public synchronized void requestPreviewFrame(Handler handler, int message) {
OpenCamera theCamera = camera;
if (theCamera != null && previewing) {
previewCallback.setHandler(handler, message);
theCamera.getCamera().setOneShotPreviewCallback(previewCallback);
}
}
/**
* Calculates the framing rect which the UI should draw to show the user where to place the
* barcode. This target helps with alignment as well as forces the user to hold the device
* far enough away to ensure the image will be in focus.
*
* @return The rectangle to draw on screen in window coordinates.
*/
public synchronized Rect getFramingRect() {
if (framingRect == null) {
if (camera == null) {
return null;
}
Point screenResolution = configManager.getScreenResolution();
if (screenResolution == null) {
// Called early, before init even finished
return null;
}
int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
int height = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
int leftOffset = (screenResolution.x - width) / 2;
int topOffset = (screenResolution.y - height) / 2;
framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
Log.d(TAG, "Calculated framing rect: " + framingRect);
}
return framingRect;
}
private static int findDesiredDimensionInRange(int resolution, int hardMin, int hardMax) {
int dim = 5 * resolution / 8; // Target 5/8 of each dimension
if (dim < hardMin) {
return hardMin;
}
if (dim > hardMax) {
return hardMax;
}
return dim;
}
/**
* Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
* not UI / screen.
*
* @return {@link Rect} expressing barcode scan area in terms of the preview size
*/
public synchronized Rect getFramingRectInPreview() {
if (framingRectInPreview == null) {
Rect framingRect = getFramingRect();
if (framingRect == null) {
return null;
}
Rect rect = new Rect(framingRect);
Point cameraResolution = configManager.getCameraResolution();
Point screenResolution = configManager.getScreenResolution();
if (cameraResolution == null || screenResolution == null) {
// Called early, before init even finished
return null;
}
rect.left = rect.left * cameraResolution.x / screenResolution.x;
rect.right = rect.right * cameraResolution.x / screenResolution.x;
rect.top = rect.top * cameraResolution.y / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
framingRectInPreview = rect;
}
return framingRectInPreview;
}
/**
* Allows third party apps to specify the camera ID, rather than determine
* it automatically based on available cameras and their orientation.
*
* @param cameraId camera ID of the camera to use. A negative value means "no preference".
*/
public synchronized void setManualCameraId(int cameraId) {
requestedCameraId = cameraId;
}
/**
* Allows third party apps to specify the scanning rectangle dimensions, rather than determine
* them automatically based on screen resolution.
*
* @param width The width in pixels to scan.
* @param height The height in pixels to scan.
*/
public synchronized void setManualFramingRect(int width, int height) {
if (initialized) {
Point screenResolution = configManager.getScreenResolution();
if (width > screenResolution.x) {
width = screenResolution.x;
}
if (height > screenResolution.y) {
height = screenResolution.y;
}
int leftOffset = (screenResolution.x - width) / 2;
int topOffset = (screenResolution.y - height) / 2;
framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
Log.d(TAG, "Calculated manual framing rect: " + framingRect);
framingRectInPreview = null;
} else {
requestedFramingRectWidth = width;
requestedFramingRectHeight = height;
}
}
/**
* A factory method to build the appropriate LuminanceSource object based on the format
* of the preview buffers, as described by Camera.Parameters.
*
* @param data A preview frame.
* @param width The width of the image.
* @param height The height of the image.
* @return A PlanarYUVLuminanceSource instance.
*/
public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
Rect rect = getFramingRectInPreview();
if (rect == null) {
return null;
}
// Go ahead and assume it's YUV rather than die.
return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
rect.width(), rect.height(), false);
}
}

View File

@@ -0,0 +1,43 @@
package com.king.zxing.camera;
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.SharedPreferences;
import com.king.zxing.Preferences;
/**
* Enumerates settings of the preference controlling the front light.
*/
public enum FrontLightMode {
/** Always on. */
ON,
/** On only when ambient light is low. */
AUTO,
/** Always off. */
OFF;
private static FrontLightMode parse(String modeString) {
return modeString == null ? OFF : valueOf(modeString);
}
public static FrontLightMode readPref(SharedPreferences sharedPrefs) {
return parse(sharedPrefs.getString(Preferences.KEY_FRONT_LIGHT_MODE, OFF.toString()));
}
}

Some files were not shown because too many files have changed in this diff Show More