Initial commit
10
.gitignore
vendored
Normal 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
@@ -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
29
.idea/codeStyles/Project.xml
generated
Normal 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
@@ -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
@@ -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
@@ -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>
|
||||||
3
.idea/markdown-navigator/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<component name="MarkdownNavigator.ProfileManager">
|
||||||
|
<settings default="" pdf-export="" />
|
||||||
|
</component>
|
||||||
34
.idea/misc.xml
generated
Normal 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
@@ -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
@@ -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
|
||||||
201
LICENSE
Normal 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
@@ -0,0 +1,112 @@
|
|||||||
|
# ZXingLite
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
[](https://raw.githubusercontent.com/jenly1314/ZXingLite/master/app/release/app-release.apk)
|
||||||
|
[](https://jitpack.io/#jenly1314/ZXingLite)
|
||||||
|
[](https://travis-ci.org/jenly1314/ZXingLite)
|
||||||
|
[](https://android-arsenal.com/api?level=15)
|
||||||
|
[](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
[](http://blog.csdn.net/jenly121)
|
||||||
|
|
||||||
|
ZXingLite for Android 是ZXing的精简版,优化扫码和生成二维码功能,扫码界面支持完全自定义,让集成更简单。
|
||||||
|
|
||||||
|
## 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>
|
||||||
|
|
||||||
|
微信公众号:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
加入QQ群: <a title="点击加入QQ群" href="http://shang.qq.com/wpa/qunwpa?idkey=8fcc6a2f88552ea44b1411582c94fd124f7bb3ec227e2a400dbbfaad3dc2f5ad" target="_blank">20867961</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1
app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
36
app/build.gradle
Normal 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
@@ -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
1
app/release/output.json
Normal 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":{}}]
|
||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
31
app/src/main/AndroidManifest.xml
Normal 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>
|
||||||
BIN
app/src/main/ic_launcher-web.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
85
app/src/main/java/com/king/zxing/app/CodeActivity.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
147
app/src/main/java/com/king/zxing/app/MainActivity.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
app/src/main/res/anim/in.xml
Normal 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" />
|
||||||
5
app/src/main/res/anim/out.xml
Normal 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" />
|
||||||
34
app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Normal 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>
|
||||||
BIN
app/src/main/res/drawable-xxhdpi/btn_back_normal.png
Normal file
|
After Width: | Height: | Size: 726 B |
BIN
app/src/main/res/drawable-xxhdpi/btn_back_pressed.png
Normal file
|
After Width: | Height: | Size: 804 B |
BIN
app/src/main/res/drawable-xxhdpi/btn_none.png
Normal file
|
After Width: | Height: | Size: 1008 B |
BIN
app/src/main/res/drawable-xxhdpi/flash_off.png
Normal file
|
After Width: | Height: | Size: 809 B |
BIN
app/src/main/res/drawable-xxhdpi/flash_on.png
Normal file
|
After Width: | Height: | Size: 712 B |
5
app/src/main/res/drawable/btn_back_selector.xml
Normal 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>
|
||||||
5
app/src/main/res/drawable/flash_selected_selector.xml
Normal 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>
|
||||||
171
app/src/main/res/drawable/ic_launcher_background.xml
Normal 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>
|
||||||
101
app/src/main/res/layout/activity_main.xml
Normal 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>
|
||||||
18
app/src/main/res/layout/code_activity.xml
Normal 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>
|
||||||
35
app/src/main/res/layout/custom_capture_activity.xml
Normal 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>
|
||||||
8
app/src/main/res/layout/easy_capture_activity.xml
Normal 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>
|
||||||
12
app/src/main/res/layout/toolbar.xml
Normal 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>
|
||||||
11
app/src/main/res/layout/toolbar_capture.xml
Normal 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>
|
||||||
35
app/src/main/res/layout/top_title_back_bar.xml
Normal 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>
|
||||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal 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>
|
||||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal 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>
|
||||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1022 B |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
4
app/src/main/res/values-v19/dimens.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<dimen name="status_bar_height">25dp</dimen>
|
||||||
|
</resources>
|
||||||
8
app/src/main/res/values/colors.xml
Normal 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>
|
||||||
12
app/src/main/res/values/dimens.xml
Normal 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>
|
||||||
4
app/src/main/res/values/ic_launcher_background.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#1FB3E2</color>
|
||||||
|
</resources>
|
||||||
5
app/src/main/res/values/ids.xml
Normal 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>
|
||||||
7
app/src/main/res/values/strings.xml
Normal 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>
|
||||||
17
app/src/main/res/values/styles.xml
Normal 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>
|
||||||
17
app/src/test/java/com/king/zxing/app/ExampleUnitTest.java
Normal 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
@@ -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
@@ -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
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal 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
@@ -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
@@ -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
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
11
lib/bintray.gradle
Normal 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
@@ -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
@@ -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
|
||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
20
lib/src/main/AndroidManifest.xml
Normal 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>
|
||||||
88
lib/src/main/java/com/king/zxing/AmbientLightManager.java
Normal 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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
136
lib/src/main/java/com/king/zxing/BeepManager.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
781
lib/src/main/java/com/king/zxing/CaptureActivity.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
169
lib/src/main/java/com/king/zxing/CaptureActivityHandler.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
105
lib/src/main/java/com/king/zxing/DecodeFormatManager.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
120
lib/src/main/java/com/king/zxing/DecodeHandler.java
Normal 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
237
lib/src/main/java/com/king/zxing/DecodeHintManager.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
114
lib/src/main/java/com/king/zxing/DecodeThread.java
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
123
lib/src/main/java/com/king/zxing/InactivityTimer.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
303
lib/src/main/java/com/king/zxing/Intents.java
Normal 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;
|
||||||
|
}
|
||||||
50
lib/src/main/java/com/king/zxing/Preferences.java
Normal 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";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
345
lib/src/main/java/com/king/zxing/ViewfinderView.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
132
lib/src/main/java/com/king/zxing/camera/AutoFocusManager.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
336
lib/src/main/java/com/king/zxing/camera/CameraManager.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
43
lib/src/main/java/com/king/zxing/camera/FrontLightMode.java
Normal 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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||