Import zxing-core 1.7 and qr_scanner
Change-Id: I0e29ab078807cc5e4f958f36ddf8dd88e627b60e
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..5668d05
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,3 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/NOTICE
@@ -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.
diff --git a/core/Android.mk b/core/Android.mk
new file mode 100644
index 0000000..b4027ed
--- /dev/null
+++ b/core/Android.mk
@@ -0,0 +1,4 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := zxing-core-1.7:core.jar
+include $(BUILD_MULTI_PREBUILT)
diff --git a/core/MODULE_LICENSE_APACHE2 b/core/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/MODULE_LICENSE_APACHE2
diff --git a/core/NOTICE b/core/NOTICE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/core/NOTICE
@@ -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.
diff --git a/core/README.google b/core/README.google
new file mode 100644
index 0000000..03c873e
--- /dev/null
+++ b/core/README.google
@@ -0,0 +1,16 @@
+URL: svn checkout -r 1937 http://zxing.googlecode.com/svn/trunk/ zxing-read-only
+
+Version: 1.7.1 (Revision: r1937)
+
+License: Apache License 2.0
+
+License File: LICENSE
+
+Description:
+ZXing (pronounced "zebra crossing") is an open-source, multi-format 1D/2D
+barcode reader library implemented in Java. Our goal is to support decoding of
+QR Codes, Data Matrix, and the UPC family of 1D barcodes. It will provide
+clients for J2ME, J2SE, and Android.
+
+Local Modifications:
+No modifications.
diff --git a/core/core.jar b/core/core.jar
new file mode 100644
index 0000000..43a3140
--- /dev/null
+++ b/core/core.jar
Binary files differ
diff --git a/qr_scanner/AndroidManifest.xml b/qr_scanner/AndroidManifest.xml
new file mode 100644
index 0000000..eb1e711
--- /dev/null
+++ b/qr_scanner/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.zxing.client.android"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="7" />
+
+ <application >
+ <activity android:name="com.google.android.youtube.CaptureActivity" />
+ </application>
+
+ <uses-permission android:name="android.permission.CAMERA" />
+</manifest>
\ No newline at end of file
diff --git a/qr_scanner/README.google b/qr_scanner/README.google
new file mode 100644
index 0000000..fe7a13a
--- /dev/null
+++ b/qr_scanner/README.google
@@ -0,0 +1,14 @@
+URL: http://code.google.com/p/zxing/
+Version: 1.7.1
+License: Apache License 2.0
+License File: LICENSE
+
+Description:
+Android library that exposes an activity to capture QR codes. It is basically
+a stripped down version of ZXing's BarcodeScanner application, with all the
+non-QR code scanning and the products, books and all other product recognition
+features remove.
+
+Local Modificaitons:
+Removed all code that is not directly related to scanning a QR code, such as product search, book
+search, 2D barcode scanning etc.
diff --git a/qr_scanner/proguard.cfg b/qr_scanner/proguard.cfg
new file mode 100644
index 0000000..b1cdf17
--- /dev/null
+++ b/qr_scanner/proguard.cfg
@@ -0,0 +1,40 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
diff --git a/qr_scanner/project.properties b/qr_scanner/project.properties
new file mode 100644
index 0000000..337e8f3
--- /dev/null
+++ b/qr_scanner/project.properties
@@ -0,0 +1,12 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-7
+android.library=true
diff --git a/qr_scanner/res/drawable-hdpi/ic_launcher.png b/qr_scanner/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/qr_scanner/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/qr_scanner/res/drawable-ldpi/ic_launcher.png b/qr_scanner/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000..1095584
--- /dev/null
+++ b/qr_scanner/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/qr_scanner/res/drawable-mdpi/ic_launcher.png b/qr_scanner/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/qr_scanner/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/qr_scanner/res/layout/capture.xml b/qr_scanner/res/layout/capture.xml
new file mode 100755
index 0000000..eb3ab3e
--- /dev/null
+++ b/qr_scanner/res/layout/capture.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <SurfaceView android:id="@+id/preview_view"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_centerInParent="true"/>
+
+ <com.google.zxing.client.android.ViewfinderView
+ android:id="@+id/viewfinder_view"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/transparent"/>
+
+ <TextView android:id="@+id/status_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|center_horizontal"
+ android:background="@color/transparent"
+ android:text="@string/msg_default_status"
+ android:textColor="@color/status_text"
+ android:textSize="14sp"/>
+
+</FrameLayout>
diff --git a/qr_scanner/res/values-ar/strings.xml b/qr_scanner/res/values-ar/strings.xml
new file mode 100644
index 0000000..a9d6968
--- /dev/null
+++ b/qr_scanner/res/values-ar/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"ضع رمز QR داخل مستطيل محدد المنظر لفحصه."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"عذرًا، لقد واجهت كاميرا Android مشكلة. قد تحتاج إلى إعادة تشغيل الجهاز."</string>
+</resources>
diff --git a/qr_scanner/res/values-bg/strings.xml b/qr_scanner/res/values-bg/strings.xml
new file mode 100644
index 0000000..bb66112
--- /dev/null
+++ b/qr_scanner/res/values-bg/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Поставете кода за бърза реакция в правоъгълника на визьора, за да го сканирате."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"За съжаление камерата на Android откри проблем. Може да се наложи да рестартирате устройството."</string>
+</resources>
diff --git a/qr_scanner/res/values-ca/strings.xml b/qr_scanner/res/values-ca/strings.xml
new file mode 100644
index 0000000..e9dec7f
--- /dev/null
+++ b/qr_scanner/res/values-ca/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Poseu un codi QR al rectangle del visor per explorar-lo."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"La càmera d\'Android ha detectat un problema. És possible que hàgiu de reiniciar el dispositiu."</string>
+</resources>
diff --git a/qr_scanner/res/values-cs/strings.xml b/qr_scanner/res/values-cs/strings.xml
new file mode 100644
index 0000000..cac83d3
--- /dev/null
+++ b/qr_scanner/res/values-cs/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Chcete-li naskenovat QR kód, umístěte jej do obdélníku hledáčku."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Došlo k potížím s fotoaparátem zařízení Android. Možná bude potřeba zařízení restartovat."</string>
+</resources>
diff --git a/qr_scanner/res/values-da/strings.xml b/qr_scanner/res/values-da/strings.xml
new file mode 100644
index 0000000..5e80f4b
--- /dev/null
+++ b/qr_scanner/res/values-da/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Placer en QR-kode inde i søgerens rektangel for at scanne den."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Der er desværre opstået et problem med Android-kameraet. Du er muligvis nødt til at genstarte enheden."</string>
+</resources>
diff --git a/qr_scanner/res/values-de/strings.xml b/qr_scanner/res/values-de/strings.xml
new file mode 100644
index 0000000..7505572
--- /dev/null
+++ b/qr_scanner/res/values-de/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Um einen QR-Code zu scannen, erfassen Sie diesen im Rechteck des Suchers."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Mit der Android-Kamera ist ein Problem aufgetreten. Sie müssen das Gerät möglicherweise neu starten."</string>
+</resources>
diff --git a/qr_scanner/res/values-el/strings.xml b/qr_scanner/res/values-el/strings.xml
new file mode 100644
index 0000000..73478e3
--- /dev/null
+++ b/qr_scanner/res/values-el/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Προσθέστε έναν κωδικό QR μέσα στο ορθογώνιο του στόχαστρου για να τον σαρώσετε."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Λυπούμαστε, παρουσιάστηκε πρόβλημα με τη φωτογραφική μηχανή Android. Ίσως χρειαστεί να πραγματοποιήσετε επανεκκίνηση της συσκευής."</string>
+</resources>
diff --git a/qr_scanner/res/values-en-rGB/strings.xml b/qr_scanner/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..1e0207d
--- /dev/null
+++ b/qr_scanner/res/values-en-rGB/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Place a QR code inside the viewfinder rectangle to scan it."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Sorry, the Android camera encountered a problem. You may need to restart the device."</string>
+</resources>
diff --git a/qr_scanner/res/values-es-rUS/strings.xml b/qr_scanner/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..6eaeb59
--- /dev/null
+++ b/qr_scanner/res/values-es-rUS/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Establece un código QR dentro del rectángulo del visor para analizarlo."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Lo sentimos, se ha producido un problema con la cámara de Android. Es posible que debas reiniciar el dispositivo."</string>
+</resources>
diff --git a/qr_scanner/res/values-es/strings.xml b/qr_scanner/res/values-es/strings.xml
new file mode 100644
index 0000000..4891bc8
--- /dev/null
+++ b/qr_scanner/res/values-es/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Coloca un código QR en el rectángulo del visor para escanearlo."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Se ha producido un error con la cámara de Android. Es posible que tengas que reiniciar el dispositivo."</string>
+</resources>
diff --git a/qr_scanner/res/values-et/strings.xml b/qr_scanner/res/values-et/strings.xml
new file mode 100644
index 0000000..bb6591f
--- /dev/null
+++ b/qr_scanner/res/values-et/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Kontrollimiseks paigutage QR-kood pildinäidiku ristkülikusse."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Kahjuks ilmnes Android-kaameraga probleem. Võib tekkida vajadus seade taaskäivitada."</string>
+</resources>
diff --git a/qr_scanner/res/values-fa/strings.xml b/qr_scanner/res/values-fa/strings.xml
new file mode 100644
index 0000000..693e0c6
--- /dev/null
+++ b/qr_scanner/res/values-fa/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"یک کد QR در داخل مستطیل نمایاب قرار دهید تا آن را اسکن کنید."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"متأسفیم، دوربین Android با مشکل مواجه شد. ممکن است لازم باشد دستگاه را مجداً راه اندازی کنید."</string>
+</resources>
diff --git a/qr_scanner/res/values-fi/strings.xml b/qr_scanner/res/values-fi/strings.xml
new file mode 100644
index 0000000..f00e9bd
--- /dev/null
+++ b/qr_scanner/res/values-fi/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Aseta QR-koodi etsimen suorakulmion sisälle lukeaksesi sen."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Virhe Android-kamerassa, pahoittelemme. Voit joutua käynnistämään laitteen uudelleen."</string>
+</resources>
diff --git a/qr_scanner/res/values-fr/strings.xml b/qr_scanner/res/values-fr/strings.xml
new file mode 100644
index 0000000..bd7dd9c
--- /dev/null
+++ b/qr_scanner/res/values-fr/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Positionnez un code 2D à l\'intérieur du rectangle du viseur pour le scanner."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Désolé, un problème est survenu au niveau de l\'appareil photo Android. Vous devrez peut-être redémarrer l\'appareil."</string>
+</resources>
diff --git a/qr_scanner/res/values-hi/strings.xml b/qr_scanner/res/values-hi/strings.xml
new file mode 100644
index 0000000..719aaf8
--- /dev/null
+++ b/qr_scanner/res/values-hi/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"दृश्यदर्शी आयत को स्कैन करने के लिए उसके अंदर एक QR कोड रखें."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"क्षमा करें, Android कैमरे में कोई समस्या आ गई है. आपको उपकरण पुन: प्रारंभ करने की आवश्यकता हो सकती है."</string>
+</resources>
diff --git a/qr_scanner/res/values-hr/strings.xml b/qr_scanner/res/values-hr/strings.xml
new file mode 100644
index 0000000..91e8596
--- /dev/null
+++ b/qr_scanner/res/values-hr/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Postavite QR kod unutar pravokutnika tražila da biste ga skenirali."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Žao nam je, Androidova kamera naišla je na problem. Možda ćete morati ponovo pokrenuti uređaj."</string>
+</resources>
diff --git a/qr_scanner/res/values-hu/strings.xml b/qr_scanner/res/values-hu/strings.xml
new file mode 100644
index 0000000..4bccf29
--- /dev/null
+++ b/qr_scanner/res/values-hu/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"A beolvasáshoz pozicionálja a QR-kódot a beolvasási mezőbe."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Elnézést kérünk, de az Android-kamera hibát észlelt. Lehet, hogy újra kell indítania az eszközt."</string>
+</resources>
diff --git a/qr_scanner/res/values-in/strings.xml b/qr_scanner/res/values-in/strings.xml
new file mode 100644
index 0000000..0f9bac6
--- /dev/null
+++ b/qr_scanner/res/values-in/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Masukkan kode QR ke dalam kotak bidang tilik untuk memindainya."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Maaf, kamera Android mengalami masalah. Anda mungkin harus memulai ulang perangkat."</string>
+</resources>
diff --git a/qr_scanner/res/values-it/strings.xml b/qr_scanner/res/values-it/strings.xml
new file mode 100644
index 0000000..1ae12b2
--- /dev/null
+++ b/qr_scanner/res/values-it/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Posiziona il rettangolo del mirino sopra il codice QR per eseguirne la scansione."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Spiacenti, si è verificato un problema con la fotocamera di Android. Potrebbe essere necessario riavviare il dispositivo."</string>
+</resources>
diff --git a/qr_scanner/res/values-iw/strings.xml b/qr_scanner/res/values-iw/strings.xml
new file mode 100644
index 0000000..75f4d96
--- /dev/null
+++ b/qr_scanner/res/values-iw/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"מקם קוד תגובה מהירה בתוך מלבן העינית כדי לסרוק אותו."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"מצטערים. מצלמת Android נתקלה בבעיה. ייתכן שתידרש להפעיל מחדש את המכשיר."</string>
+</resources>
diff --git a/qr_scanner/res/values-ja/strings.xml b/qr_scanner/res/values-ja/strings.xml
new file mode 100644
index 0000000..3acdff6
--- /dev/null
+++ b/qr_scanner/res/values-ja/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"QRコードをスキャンするには、ファインダーの四角形でQRコードを写してください。"</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Androidカメラで問題が発生しました。携帯端末の再起動をおすすめします。"</string>
+</resources>
diff --git a/qr_scanner/res/values-ko/strings.xml b/qr_scanner/res/values-ko/strings.xml
new file mode 100644
index 0000000..ea6ca46
--- /dev/null
+++ b/qr_scanner/res/values-ko/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"QR 코드를 스캔하려면 화면에 표시되는 사각형 안에 놓으세요."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"죄송합니다. Android 카메라에 문제가 발생했습니다. 기기를 다시 시작해야 할 수 있습니다."</string>
+</resources>
diff --git a/qr_scanner/res/values-lt/strings.xml b/qr_scanner/res/values-lt/strings.xml
new file mode 100644
index 0000000..b6a411b
--- /dev/null
+++ b/qr_scanner/res/values-lt/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Jei norite nuskaityti QR kodą, jis turi būti vaizdo ieškiklio stačiakampyje."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Apgailestaujame, bet iškilo su „Android“ fotoaparatu susijusi problema. Gali reikėti iš naujo paleisti įrenginį."</string>
+</resources>
diff --git a/qr_scanner/res/values-lv/strings.xml b/qr_scanner/res/values-lv/strings.xml
new file mode 100644
index 0000000..8a9097b
--- /dev/null
+++ b/qr_scanner/res/values-lv/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Lai skenētu ātrās atbildes kodu, ievietojiet to skatu meklētāja taisnstūrī."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Diemžēl Android kamerā radās problēma. Iespējams, jārestartē ierīce."</string>
+</resources>
diff --git a/qr_scanner/res/values-ms/strings.xml b/qr_scanner/res/values-ms/strings.xml
new file mode 100644
index 0000000..6210979
--- /dev/null
+++ b/qr_scanner/res/values-ms/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Letakkan kod QR di dalam segi empat tepat pemidang tilik untuk mengimbasnya."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Maaf, kamera Android menghadapai masalah. Anda mungkin perlu memulakan semula peranti ini."</string>
+</resources>
diff --git a/qr_scanner/res/values-nb/strings.xml b/qr_scanner/res/values-nb/strings.xml
new file mode 100644
index 0000000..c3f1d98
--- /dev/null
+++ b/qr_scanner/res/values-nb/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Plasser en QR-kode inne i synsvinkelrektanglet for å skanne den."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Beklager, men det oppsto et problem med Android-kameraet. Forsøk å starte enheten på nytt."</string>
+</resources>
diff --git a/qr_scanner/res/values-nl/strings.xml b/qr_scanner/res/values-nl/strings.xml
new file mode 100644
index 0000000..d169817
--- /dev/null
+++ b/qr_scanner/res/values-nl/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Plaats een QR-code in de rechthoek van de beeldzoeker om de code te scannen."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Er is een probleem met de Android-camera opgetreden. U moet het apparaat mogelijk opnieuw opstarten."</string>
+</resources>
diff --git a/qr_scanner/res/values-pl/strings.xml b/qr_scanner/res/values-pl/strings.xml
new file mode 100644
index 0000000..36d527e
--- /dev/null
+++ b/qr_scanner/res/values-pl/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Wyśrodkuj kod QR w prostokącie, by go zeskanować."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Niestety, wystąpił problem z obsługą aparatu w Androidzie. Może być konieczne ponowne uruchomienie urządzenia."</string>
+</resources>
diff --git a/qr_scanner/res/values-pt-rPT/strings.xml b/qr_scanner/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..12165e9
--- /dev/null
+++ b/qr_scanner/res/values-pt-rPT/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Coloque um código QR dentro do retângulo do visor para o ler."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"A câmara do Android encontrou um problema. Poderá ser necessário reiniciar o aparelho."</string>
+</resources>
diff --git a/qr_scanner/res/values-pt/strings.xml b/qr_scanner/res/values-pt/strings.xml
new file mode 100644
index 0000000..f119e3f
--- /dev/null
+++ b/qr_scanner/res/values-pt/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Coloque um código QR dentro do retângulo do visor para digitalizá-lo."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"A câmera do Android encontrou um problema. Talvez seja necessário reiniciar o dispositivo."</string>
+</resources>
diff --git a/qr_scanner/res/values-ro/strings.xml b/qr_scanner/res/values-ro/strings.xml
new file mode 100644
index 0000000..debf996
--- /dev/null
+++ b/qr_scanner/res/values-ro/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Pentru a scana un cod QR, plasaţi-l în interiorul dreptunghiului vizorului."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Ne pare rău, dar camera foto Android a întâmpinat o problemă. Ar putea fi nevoie să reporniţi dispozitivul."</string>
+</resources>
diff --git a/qr_scanner/res/values-ru/strings.xml b/qr_scanner/res/values-ru/strings.xml
new file mode 100644
index 0000000..3abcf5c
--- /dev/null
+++ b/qr_scanner/res/values-ru/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Чтобы отсканировать QR-код, наведите на него рамку видоискателя."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Ошибка камеры Android. Перезапустите устройство."</string>
+</resources>
diff --git a/qr_scanner/res/values-sk/strings.xml b/qr_scanner/res/values-sk/strings.xml
new file mode 100644
index 0000000..5f9f769
--- /dev/null
+++ b/qr_scanner/res/values-sk/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Ak chcete naskenovať kód QR, umiestnite ho do obdĺžnika hľadáčika."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Je nám ľúto, vyskytol sa problém s fotoaparátom v zariadení so systémom Android. Možno budete musieť zariadenie reštartovať."</string>
+</resources>
diff --git a/qr_scanner/res/values-sl/strings.xml b/qr_scanner/res/values-sl/strings.xml
new file mode 100644
index 0000000..512e156
--- /dev/null
+++ b/qr_scanner/res/values-sl/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Če želite optično prebrati kodo QR, jo postavite v pravokotnik iskala."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Težava v fotoaparatu Android. Morda bo treba znova zagnati napravo."</string>
+</resources>
diff --git a/qr_scanner/res/values-sr/strings.xml b/qr_scanner/res/values-sr/strings.xml
new file mode 100644
index 0000000..8eb152b
--- /dev/null
+++ b/qr_scanner/res/values-sr/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Поставите QR кôд у правоугаоник визира да бисте га скенирали."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Нажалост, Android камера је наишла на проблем. Можда ћете морати поново да покренете уређај."</string>
+</resources>
diff --git a/qr_scanner/res/values-sv/strings.xml b/qr_scanner/res/values-sv/strings.xml
new file mode 100644
index 0000000..db522af
--- /dev/null
+++ b/qr_scanner/res/values-sv/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Placera QR-koden i sökarens rektangel om du vill skanna den."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Det uppstod ett problem med Android-kameran. Du måste eventuellt starta om enheten."</string>
+</resources>
diff --git a/qr_scanner/res/values-th/strings.xml b/qr_scanner/res/values-th/strings.xml
new file mode 100644
index 0000000..da681ca
--- /dev/null
+++ b/qr_scanner/res/values-th/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"เล็งให้โค้ด QR อยู่ในสี่เหลี่ยมช่องมองภาพเพื่อทำการสแกน"</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"ขออภัย เกิดปัญหากับกล้องถ่ายรูปแอนดรอยด์ คุณอาจต้องรีสตาร์ทอุปกรณ์"</string>
+</resources>
diff --git a/qr_scanner/res/values-tl/strings.xml b/qr_scanner/res/values-tl/strings.xml
new file mode 100644
index 0000000..c79eb80
--- /dev/null
+++ b/qr_scanner/res/values-tl/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Maglagay ng QR code sa loob ng parihaba ng viewfinder upang i-scan ito."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Paumanhin, nakatagpo ng problema ang camera ng Android. Maaaring kailanganin mong i-restart ang device."</string>
+</resources>
diff --git a/qr_scanner/res/values-tr/strings.xml b/qr_scanner/res/values-tr/strings.xml
new file mode 100644
index 0000000..0fe38b7
--- /dev/null
+++ b/qr_scanner/res/values-tr/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Taranacak QR kodunu vizör çerçevesinin içine yerleştirin."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Maalesef, Android kamera bir sorunla karşılaştı. Cihazı yeniden başlatmanız gerekebilir."</string>
+</resources>
diff --git a/qr_scanner/res/values-uk/strings.xml b/qr_scanner/res/values-uk/strings.xml
new file mode 100644
index 0000000..10c37b7
--- /dev/null
+++ b/qr_scanner/res/values-uk/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Щоб зісканувати QR-код, розмістіть його в прямокутнику видошукача."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"На жаль, виникла проблема з камерою Android. Можливо, потрібно перезавантажити пристрій."</string>
+</resources>
diff --git a/qr_scanner/res/values-vi/strings.xml b/qr_scanner/res/values-vi/strings.xml
new file mode 100644
index 0000000..eefe895
--- /dev/null
+++ b/qr_scanner/res/values-vi/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"Đưa mã QR vào bên trong hình chữ nhật của kính ngắm để quét mã."</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"Rất tiếc, máy ảnh Android đã gặp sự cố. Bạn có thể cần khởi động lại thiết bị."</string>
+</resources>
diff --git a/qr_scanner/res/values-zh-rCN/strings.xml b/qr_scanner/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..3cead54
--- /dev/null
+++ b/qr_scanner/res/values-zh-rCN/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"将 QR 码放在取景器的矩形框内以便对它进行扫描。"</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"抱歉,此 Android 相机遇到问题,您可能需要重新启动此设备。"</string>
+</resources>
diff --git a/qr_scanner/res/values-zh-rTW/strings.xml b/qr_scanner/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..15fa162
--- /dev/null
+++ b/qr_scanner/res/values-zh-rTW/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="msg_default_status" msgid="639431501805022060">"將 QR 圖碼置入取景器的方框中即可開始掃描。"</string>
+ <string name="msg_camera_framework_bug" msgid="2167124836274973533">"很抱歉,Android 相機發生問題。您可能需要重新啟動裝置。"</string>
+</resources>
diff --git a/qr_scanner/res/values/colors.xml b/qr_scanner/res/values/colors.xml
new file mode 100644
index 0000000..f74f1be
--- /dev/null
+++ b/qr_scanner/res/values/colors.xml
@@ -0,0 +1,25 @@
+<resources>
+<color name="contents_text">#ff000000</color>
+<color name="encode_view">#ffffffff</color>
+<color name="help_button_view">#ffcccccc</color>
+<color name="help_view">#ff404040</color>
+<color name="possible_result_points">#c0ffff00</color>
+<color name="result_image_border">#ffffffff</color>
+<color name="result_minor_text">#ffc0c0c0</color>
+<color name="result_points">#c000ff00</color>
+<color name="result_text">#ffffffff</color>
+<color name="result_view">#b0000000</color>
+<color name="sbc_header_text">#ff808080</color>
+<color name="sbc_header_view">#ffffffff</color>
+<color name="sbc_list_item">#fffff0e0</color>
+<color name="sbc_layout_view">#ffffffff</color>
+<color name="sbc_page_number_text">#ff000000</color>
+<color name="sbc_snippet_text">#ff4b4b4b</color>
+<color name="share_text">#ff000000</color>
+<color name="status_view">#50000000</color>
+<color name="status_text">#ffffffff</color>
+<color name="transparent">#00000000</color>
+<color name="viewfinder_frame">#ff000000</color>
+<color name="viewfinder_laser">#ffff0000</color>
+<color name="viewfinder_mask">#60000000</color>
+</resources>
\ No newline at end of file
diff --git a/qr_scanner/res/values/ids.xml b/qr_scanner/res/values/ids.xml
new file mode 100644
index 0000000..9739982
--- /dev/null
+++ b/qr_scanner/res/values/ids.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <!-- Messages IDs -->
+ <item type="id" name="auto_focus"/>
+ <item type="id" name="decode"/>
+ <item type="id" name="decode_failed"/>
+ <item type="id" name="decode_succeeded"/>
+ <item type="id" name="launch_product_query"/>
+ <item type="id" name="quit"/>
+ <item type="id" name="restart_preview"/>
+ <item type="id" name="return_scan_result"/>
+ <item type="id" name="search_book_contents_failed"/>
+ <item type="id" name="search_book_contents_succeeded"/>
+</resources>
diff --git a/qr_scanner/res/values/strings.xml b/qr_scanner/res/values/strings.xml
new file mode 100644
index 0000000..f574077
--- /dev/null
+++ b/qr_scanner/res/values/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- Caption shown below the viewfinder rectangle, explaining how to scan a QR code [CHAR LIMIT=NONE] -->
+ <string name="msg_default_status">Place a QR code inside the viewfinder rectangle to scan it.</string>
+ <!-- Error message displayed when starting up the phone/tablet's camera to scan a QR code has failed [CHAR LIMIT=NONE] -->
+ <string name="msg_camera_framework_bug">Sorry, the Android camera encountered a problem. You may need to restart the device.</string>
+</resources>
\ No newline at end of file
diff --git a/qr_scanner/src/com/google/zxing/client/android/CaptureActivity.java b/qr_scanner/src/com/google/zxing/client/android/CaptureActivity.java
new file mode 100755
index 0000000..c65aadf
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/CaptureActivity.java
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.Result;
+import com.google.zxing.ResultPoint;
+import com.google.zxing.client.android.camera.CameraManager;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import java.io.IOException;
+
+/**
+ * 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 final class CaptureActivity extends Activity implements SurfaceHolder.Callback {
+
+ private static final String LOG_TAG = CaptureActivity.class.getCanonicalName();
+
+ private CameraManager cameraManager;
+ private CaptureActivityHandler handler;
+ private ViewfinderView viewfinderView;
+ private TextView statusView;
+ private boolean hasSurface;
+ private String characterSet;
+ private InactivityTimer inactivityTimer;
+
+ ViewfinderView getViewfinderView() {
+ return viewfinderView;
+ }
+
+ public Handler getHandler() {
+ return handler;
+ }
+
+ CameraManager getCameraManager() {
+ return cameraManager;
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ Window window = getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ setContentView(R.layout.capture);
+
+ statusView = (TextView) findViewById(R.id.status_view);
+ handler = null;
+ hasSurface = false;
+ inactivityTimer = new InactivityTimer(this);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ // 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 = (ViewfinderView) findViewById(R.id.viewfinder_view);
+ viewfinderView.setCameraManager(cameraManager);
+
+ resetStatusView();
+
+ SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
+ 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);
+ surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+ }
+
+ Intent intent = getIntent();
+ String action = intent == null ? null : intent.getAction();
+ String dataString = intent == null ? null : intent.getDataString();
+ if (intent != null && action != null) {
+ if (action.equals(Intents.Scan.ACTION)) {
+ 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);
+ }
+ }
+ }
+ characterSet = intent.getStringExtra(Intents.Scan.CHARACTER_SET);
+ } else {
+ finish();
+ }
+
+ inactivityTimer.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ if (handler != null) {
+ handler.quitSynchronously();
+ handler = null;
+ }
+ inactivityTimer.onPause();
+ cameraManager.closeDriver();
+ if (!hasSurface) {
+ SurfaceView 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) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ setResult(RESULT_CANCELED);
+ finish();
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_FOCUS || keyCode == KeyEvent.KEYCODE_CAMERA) {
+ // Handle these events so they don't launch the Camera app
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ public void surfaceCreated(SurfaceHolder holder) {
+ if (holder == null) {
+ Log.e(LOG_TAG, "*** WARNING *** surfaceCreated() gave us a null surface!");
+ }
+ if (!hasSurface) {
+ hasSurface = true;
+ initCamera(holder);
+ }
+ }
+
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ hasSurface = false;
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+
+ }
+
+ /**
+ * A valid barcode has been found, so give an indication of success and show
+ * the results.
+ *
+ * @param rawResult The contents of the barcode.
+ * @param barcode A greyscale bitmap of the camera data which was decoded.
+ */
+ public void handleDecode(Result rawResult, Bitmap barcode) {
+ inactivityTimer.onActivity();
+
+ if (barcode == null) {
+ Log.e(LOG_TAG, "Barcode not recognized");
+ setResult(RESULT_CANCELED, null);
+ } else {
+ drawResultPoints(barcode, rawResult);
+ Log.d(LOG_TAG, "Barcode is: " + rawResult.getText());
+ Intent result = new Intent();
+ result.putExtra("SCAN_RESULT", rawResult.getText());
+ setResult(RESULT_OK, result);
+ }
+ finish();
+ }
+
+ /**
+ * 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 rawResult The decoded results which contains the points to draw.
+ */
+ private void drawResultPoints(Bitmap barcode, 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_image_border));
+ paint.setStrokeWidth(3.0f);
+ paint.setStyle(Paint.Style.STROKE);
+ Rect border = new Rect(2, 2, barcode.getWidth() - 2, barcode.getHeight() - 2);
+ canvas.drawRect(border, paint);
+
+ paint.setColor(getResources().getColor(R.color.result_points));
+ if (points.length == 2) {
+ paint.setStrokeWidth(4.0f);
+ drawLine(canvas, paint, points[0], points[1]);
+ } 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]);
+ drawLine(canvas, paint, points[2], points[3]);
+ } else {
+ paint.setStrokeWidth(10.0f);
+ for (ResultPoint point : points) {
+ canvas.drawPoint(point.getX(), point.getY(), paint);
+ }
+ }
+ }
+ }
+
+ private static void drawLine(Canvas canvas, Paint paint, ResultPoint a, ResultPoint b) {
+ canvas.drawLine(a.getX(), a.getY(), b.getX(), b.getY(), paint);
+ }
+
+ private void initCamera(SurfaceHolder surfaceHolder) {
+ try {
+ cameraManager.openDriver(surfaceHolder);
+ // Creating the handler starts the preview, which can also throw a
+ // RuntimeException.
+ if (handler == null) {
+ handler = new CaptureActivityHandler(this, characterSet, cameraManager);
+ }
+ } catch (IOException ioe) {
+ Log.w(LOG_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(LOG_TAG, "Unexpected error initializing camera", e);
+ displayFrameworkBugMessageAndExit();
+ }
+ }
+
+ private void displayFrameworkBugMessageAndExit() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("");
+ builder.setMessage(getString(R.string.msg_camera_framework_bug));
+ builder.setPositiveButton(android.R.string.ok, new FinishListener(this));
+ builder.setOnCancelListener(new FinishListener(this));
+ builder.show();
+ }
+
+ private void resetStatusView() {
+ statusView.setText(R.string.msg_default_status);
+ statusView.setVisibility(View.VISIBLE);
+ viewfinderView.setVisibility(View.VISIBLE);
+ }
+
+ public void drawViewfinder() {
+ viewfinderView.drawViewfinder();
+ }
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/CaptureActivityHandler.java b/qr_scanner/src/com/google/zxing/client/android/CaptureActivityHandler.java
new file mode 100755
index 0000000..71751a4
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/CaptureActivityHandler.java
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android;
+
+import com.google.zxing.Result;
+import com.google.zxing.client.android.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;
+
+/**
+ * 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,
+ String characterSet,
+ CameraManager cameraManager) {
+ this.activity = activity;
+ decodeThread = new DecodeThread(activity, 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.auto_focus) {
+ //Log.d(TAG, "Got auto-focus message");
+ // When one auto focus pass finishes, start another. This is the closest thing to
+ // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
+ if (state == State.PREVIEW) {
+ cameraManager.requestAutoFocus(this, R.id.auto_focus);
+ }
+ } else if (message.what == R.id.restart_preview) {
+ Log.d(TAG, "Got restart preview message");
+ restartPreviewAndDecode();
+ } else if (message.what == R.id.decode_succeeded) {
+ Log.d(TAG, "Got decode succeeded message");
+ state = State.SUCCESS;
+ Bundle bundle = message.getData();
+ Bitmap barcode = bundle == null ? null :
+ (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
+ activity.handleDecode((Result) message.obj, barcode);
+ } 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) {
+ Log.d(TAG, "Got return scan result message");
+ activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
+ activity.finish();
+ } else if (message.what == R.id.launch_product_query) {
+ Log.d(TAG, "Got product query message");
+ String url = (String) message.obj;
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ activity.startActivity(intent);
+ }
+ }
+
+ 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);
+ cameraManager.requestAutoFocus(this, R.id.auto_focus);
+ activity.drawViewfinder();
+ }
+ }
+
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/DecodeHandler.java b/qr_scanner/src/com/google/zxing/client/android/DecodeHandler.java
new file mode 100644
index 0000000..dfc0043
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/DecodeHandler.java
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android;
+
+import com.google.zxing.BinaryBitmap;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.MultiFormatReader;
+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.util.Hashtable;
+
+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, Hashtable<DecodeHintType,Object> hints) {
+ multiFormatReader = new MultiFormatReader();
+ multiFormatReader.setHints(hints);
+ this.activity = activity;
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ if (!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();
+ bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
+ message.setData(bundle);
+ message.sendToTarget();
+ }
+ } else {
+ if (handler != null) {
+ Message message = Message.obtain(handler, R.id.decode_failed);
+ message.sendToTarget();
+ }
+ }
+ }
+
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/DecodeThread.java b/qr_scanner/src/com/google/zxing/client/android/DecodeThread.java
new file mode 100755
index 0000000..70ea0c0
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/DecodeThread.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.ResultPointCallback;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.Hashtable;
+import java.util.Vector;
+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";
+
+ private final CaptureActivity activity;
+ private final Hashtable<DecodeHintType,Object> hints;
+ private Handler handler;
+ private final CountDownLatch handlerInitLatch;
+
+ DecodeThread(CaptureActivity activity,
+ String characterSet,
+ ResultPointCallback resultPointCallback) {
+
+ this.activity = activity;
+ handlerInitLatch = new CountDownLatch(1);
+
+ hints = new Hashtable<DecodeHintType,Object>();
+ Vector<BarcodeFormat> formats = new Vector<BarcodeFormat>();
+ formats.add(BarcodeFormat.QR_CODE);
+ hints.put(DecodeHintType.POSSIBLE_FORMATS, formats);
+
+ if (characterSet != null) {
+ hints.put(DecodeHintType.CHARACTER_SET, characterSet);
+ }
+ hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback);
+ }
+
+ 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();
+ }
+
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/FinishListener.java b/qr_scanner/src/com/google/zxing/client/android/FinishListener.java
new file mode 100644
index 0000000..e8c8813
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/FinishListener.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+
+/**
+ * Simple listener used to exit the app in a few cases.
+ *
+ * @author Sean Owen
+ */
+public final class FinishListener
+ implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener, Runnable {
+
+ private final Activity activityToFinish;
+
+ public FinishListener(Activity activityToFinish) {
+ this.activityToFinish = activityToFinish;
+ }
+
+ public void onCancel(DialogInterface dialogInterface) {
+ run();
+ }
+
+ public void onClick(DialogInterface dialogInterface, int i) {
+ run();
+ }
+
+ public void run() {
+ activityToFinish.finish();
+ }
+
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/InactivityTimer.java b/qr_scanner/src/com/google/zxing/client/android/InactivityTimer.java
new file mode 100644
index 0000000..2883fba
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/InactivityTimer.java
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Finishes an activity after a period of inactivity if the device is on battery power.
+ */
+final class InactivityTimer {
+
+ private static final int INACTIVITY_DELAY_SECONDS = 5 * 60;
+
+ private final ScheduledExecutorService inactivityTimer =
+ Executors.newSingleThreadScheduledExecutor(new DaemonThreadFactory());
+ private final Activity activity;
+ private ScheduledFuture<?> inactivityFuture = null;
+ private final BroadcastReceiver powerStatusReceiver = new PowerStatusReceiver();
+
+ InactivityTimer(Activity activity) {
+ this.activity = activity;
+ onActivity();
+ }
+
+ void onActivity() {
+ cancel();
+ if (!inactivityTimer.isShutdown()) {
+ try {
+ inactivityFuture = inactivityTimer.schedule(new FinishListener(activity),
+ INACTIVITY_DELAY_SECONDS,
+ TimeUnit.SECONDS);
+ } catch (RejectedExecutionException ree) {
+ // surprising, but could be normal if for some reason the implementation just doesn't
+ // think it can shcedule again. Since this time-out is non-essential, just forget it
+ }
+ }
+ }
+
+ public void onPause() {
+ cancel();
+ activity.unregisterReceiver(powerStatusReceiver);
+ }
+
+ public void onResume(){
+ activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ onActivity();
+ }
+
+ private void cancel() {
+ ScheduledFuture<?> future = inactivityFuture;
+ if (future != null) {
+ future.cancel(true);
+ inactivityFuture = null;
+ }
+ }
+
+ void shutdown() {
+ cancel();
+ inactivityTimer.shutdown();
+ }
+
+ private static final class DaemonThreadFactory implements ThreadFactory {
+ public Thread newThread(Runnable runnable) {
+ Thread thread = new Thread(runnable);
+ thread.setDaemon(true);
+ return thread;
+ }
+ }
+
+ 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
+ // In Android 2.0+, use BatteryManager.EXTRA_PLUGGED
+ int batteryPlugged = intent.getIntExtra("plugged", -1);
+ if (batteryPlugged > 0) {
+ InactivityTimer.this.cancel();
+ }
+ }
+ }
+ }
+
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/Intents.java b/qr_scanner/src/com/google/zxing/client/android/Intents.java
new file mode 100755
index 0000000..2bb1805
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/Intents.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android;
+
+/**
+ * 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() {
+ }
+
+ 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.YOUTUBE_SCAN";
+
+ /**
+ * @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";
+
+ private Scan() {
+ }
+ }
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/PlanarYUVLuminanceSource.java b/qr_scanner/src/com/google/zxing/client/android/PlanarYUVLuminanceSource.java
new file mode 100644
index 0000000..ed0a8a3
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/PlanarYUVLuminanceSource.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 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.
+ */
+
+package com.google.zxing.client.android;
+
+import com.google.zxing.LuminanceSource;
+
+import android.graphics.Bitmap;
+
+/**
+ * This object extends LuminanceSource around an array of YUV data returned from the camera driver,
+ * with the option to crop to a rectangle within the full data. This can be used to exclude
+ * superfluous pixels around the perimeter and speed up decoding.
+ *
+ * It works for any pixel format where the Y channel is planar and appears first, including
+ * YCbCr_420_SP and YCbCr_422_SP.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class PlanarYUVLuminanceSource extends LuminanceSource {
+
+ private final byte[] yuvData;
+ private final int dataWidth;
+ private final int dataHeight;
+ private final int left;
+ private final int top;
+
+ public PlanarYUVLuminanceSource(byte[] yuvData, int dataWidth, int dataHeight, int left, int top,
+ int width, int height, boolean reverseHorizontal) {
+ super(width, height);
+
+ if (left + width > dataWidth || top + height > dataHeight) {
+ throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
+ }
+
+ this.yuvData = yuvData;
+ this.dataWidth = dataWidth;
+ this.dataHeight = dataHeight;
+ this.left = left;
+ this.top = top;
+ if (reverseHorizontal) {
+ reverseHorizontal(width, height);
+ }
+ }
+
+ @Override
+ public byte[] getRow(int y, byte[] row) {
+ if (y < 0 || y >= getHeight()) {
+ throw new IllegalArgumentException("Requested row is outside the image: " + y);
+ }
+ int width = getWidth();
+ if (row == null || row.length < width) {
+ row = new byte[width];
+ }
+ int offset = (y + top) * dataWidth + left;
+ System.arraycopy(yuvData, offset, row, 0, width);
+ return row;
+ }
+
+ @Override
+ public byte[] getMatrix() {
+ int width = getWidth();
+ int height = getHeight();
+
+ // If the caller asks for the entire underlying image, save the copy and give them the
+ // original data. The docs specifically warn that result.length must be ignored.
+ if (width == dataWidth && height == dataHeight) {
+ return yuvData;
+ }
+
+ int area = width * height;
+ byte[] matrix = new byte[area];
+ int inputOffset = top * dataWidth + left;
+
+ // If the width matches the full width of the underlying data, perform a single copy.
+ if (width == dataWidth) {
+ System.arraycopy(yuvData, inputOffset, matrix, 0, area);
+ return matrix;
+ }
+
+ // Otherwise copy one cropped row at a time.
+ byte[] yuv = yuvData;
+ for (int y = 0; y < height; y++) {
+ int outputOffset = y * width;
+ System.arraycopy(yuv, inputOffset, matrix, outputOffset, width);
+ inputOffset += dataWidth;
+ }
+ return matrix;
+ }
+
+ @Override
+ public boolean isCropSupported() {
+ return true;
+ }
+
+ public Bitmap renderCroppedGreyscaleBitmap() {
+ int width = getWidth();
+ int height = getHeight();
+ int[] pixels = new int[width * height];
+ byte[] yuv = yuvData;
+ int inputOffset = top * dataWidth + left;
+
+ for (int y = 0; y < height; y++) {
+ int outputOffset = y * width;
+ for (int x = 0; x < width; x++) {
+ int grey = yuv[inputOffset + x] & 0xff;
+ pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101);
+ }
+ inputOffset += dataWidth;
+ }
+
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
+ return bitmap;
+ }
+
+ private void reverseHorizontal(int width, int height) {
+ byte[] yuvData = this.yuvData;
+ for (int y = 0, rowStart = top * dataWidth + left; y < height; y++, rowStart += dataWidth) {
+ int middle = rowStart + width / 2;
+ for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) {
+ byte temp = yuvData[x1];
+ yuvData[x1] = yuvData[x2];
+ yuvData[x2] = temp;
+ }
+ }
+ }
+
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/ViewfinderResultPointCallback.java b/qr_scanner/src/com/google/zxing/client/android/ViewfinderResultPointCallback.java
new file mode 100644
index 0000000..3754769
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/ViewfinderResultPointCallback.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android;
+
+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;
+ }
+
+ public void foundPossibleResultPoint(ResultPoint point) {
+ viewfinderView.addPossibleResultPoint(point);
+ }
+
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/ViewfinderView.java b/qr_scanner/src/com/google/zxing/client/android/ViewfinderView.java
new file mode 100755
index 0000000..7ec9e3e
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/ViewfinderView.java
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android;
+
+import com.google.zxing.ResultPoint;
+import com.google.zxing.client.android.camera.CameraManager;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+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 = 80L;
+ private static final int CURRENT_POINT_OPACITY = 0xA0;
+ private static final int MAX_RESULT_POINTS = 20;
+ private static final int POINT_SIZE = 6;
+
+ private CameraManager cameraManager;
+ private final Paint paint;
+ private Bitmap resultBitmap;
+ private final int maskColor;
+ private final int resultColor;
+ private final int frameColor;
+ private final int laserColor;
+ private final int resultPointColor;
+ private int scannerAlpha;
+ private List<ResultPoint> possibleResultPoints;
+ private List<ResultPoint> lastPossibleResultPoints;
+
+ // This constructor is used when the class is built from an XML resource.
+ public ViewfinderView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ // Initialize these once for performance rather than calling them every time in onDraw().
+ paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ Resources resources = getResources();
+ maskColor = resources.getColor(R.color.viewfinder_mask);
+ resultColor = resources.getColor(R.color.result_view);
+ frameColor = resources.getColor(R.color.viewfinder_frame);
+ laserColor = resources.getColor(R.color.viewfinder_laser);
+ resultPointColor = resources.getColor(R.color.possible_result_points);
+ scannerAlpha = 0;
+ possibleResultPoints = new ArrayList<ResultPoint>(5);
+ lastPossibleResultPoints = null;
+ }
+
+ public void setCameraManager(CameraManager cameraManager) {
+ this.cameraManager = cameraManager;
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ Rect frame = cameraManager.getFramingRect();
+ if (frame == null) {
+ return;
+ }
+ int width = canvas.getWidth();
+ int height = canvas.getHeight();
+
+ // Draw the exterior (i.e. outside the framing rect) darkened
+ paint.setColor(resultBitmap != null ? resultColor : 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);
+
+ 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 two pixel solid black border inside the framing rect
+ 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 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;
+ int middle = frame.height() / 2 + frame.top;
+ canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
+
+ Rect previewFrame = cameraManager.getFramingRectInPreview();
+ 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<ResultPoint>(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) {
+ for (ResultPoint point : currentLast) {
+ canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
+ frameTop + (int) (point.getY() * scaleY),
+ POINT_SIZE / 2, 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);
+ }
+ }
+
+ 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 (point) {
+ points.add(point);
+ int size = points.size();
+ if (size > MAX_RESULT_POINTS) {
+ // trim it
+ points.subList(0, size - MAX_RESULT_POINTS / 2).clear();
+ }
+ }
+ }
+
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/camera/AutoFocusCallback.java b/qr_scanner/src/com/google/zxing/client/android/camera/AutoFocusCallback.java
new file mode 100644
index 0000000..1e3f199
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/camera/AutoFocusCallback.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android.camera;
+
+import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+final class AutoFocusCallback implements Camera.AutoFocusCallback {
+
+ private static final String TAG = AutoFocusCallback.class.getSimpleName();
+
+ private static final long AUTOFOCUS_INTERVAL_MS = 1500L;
+
+ private Handler autoFocusHandler;
+ private int autoFocusMessage;
+
+ void setHandler(Handler autoFocusHandler, int autoFocusMessage) {
+ this.autoFocusHandler = autoFocusHandler;
+ this.autoFocusMessage = autoFocusMessage;
+ }
+
+ public void onAutoFocus(boolean success, Camera camera) {
+ if (autoFocusHandler != null) {
+ Message message = autoFocusHandler.obtainMessage(autoFocusMessage, success);
+ // Simulate continuous autofocus by sending a focus request every
+ // AUTOFOCUS_INTERVAL_MS milliseconds.
+ //Log.d(TAG, "Got auto-focus callback; requesting another");
+ autoFocusHandler.sendMessageDelayed(message, AUTOFOCUS_INTERVAL_MS);
+ autoFocusHandler = null;
+ } else {
+ Log.d(TAG, "Got auto-focus callback, but no handler for it");
+ }
+ }
+
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java b/qr_scanner/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java
new file mode 100644
index 0000000..6a694b0
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/camera/CameraConfigurationManager.java
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android.camera;
+
+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.WindowManager;
+
+import java.util.Collection;
+
+/**
+ * A class which deals with reading, parsing, and setting the camera parameters which are used to
+ * configure the camera hardware.
+ */
+final class CameraConfigurationManager {
+
+ private static final String TAG = "CameraConfiguration";
+ private static final int MIN_PREVIEW_PIXELS = 320 * 240; // small screen
+ private static final int MAX_PREVIEW_PIXELS = 800 * 480; // large/HD screen
+
+ private final Context context;
+ private Point screenResolution;
+ private Point cameraResolution;
+
+ CameraConfigurationManager(Context context) {
+ this.context = context;
+ }
+
+ /**
+ * Reads, one time, values from the camera that are needed by the app.
+ */
+ void initFromCameraParameters(Camera camera) {
+ Camera.Parameters parameters = camera.getParameters();
+ WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ Display display = manager.getDefaultDisplay();
+ int width = display.getWidth();
+ int height = display.getHeight();
+ // We're landscape-only, and have apparently seen issues with display thinking it's portrait
+ // when waking from sleep. If it's not landscape, assume it's mistaken and reverse them:
+ if (width < height) {
+ Log.i(TAG, "Display reports portrait orientation; assuming this is incorrect");
+ int temp = width;
+ width = height;
+ height = temp;
+ }
+ screenResolution = new Point(width, height);
+ Log.i(TAG, "Screen resolution: " + screenResolution);
+ cameraResolution = findBestPreviewSizeValue(parameters, screenResolution, false);
+ Log.i(TAG, "Camera resolution: " + cameraResolution);
+ }
+
+ void setDesiredCameraParameters(Camera camera) {
+ Camera.Parameters parameters = camera.getParameters();
+
+ if (parameters == null) {
+ Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration.");
+ return;
+ }
+
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+
+ initializeTorch(parameters, prefs);
+ String focusMode = findSettableValue(parameters.getSupportedFocusModes(),
+ Camera.Parameters.FOCUS_MODE_AUTO,
+ Camera.Parameters.FOCUS_MODE_MACRO);
+ if (focusMode != null) {
+ parameters.setFocusMode(focusMode);
+ }
+
+ parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
+ camera.setParameters(parameters);
+ }
+
+ Point getCameraResolution() {
+ return cameraResolution;
+ }
+
+ Point getScreenResolution() {
+ return screenResolution;
+ }
+
+ void setTorch(Camera camera, boolean newSetting) {
+ Camera.Parameters parameters = camera.getParameters();
+ doSetTorch(parameters, newSetting);
+ camera.setParameters(parameters);
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ boolean currentSetting = false; // prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false);
+// if (currentSetting != newSetting) {
+// SharedPreferences.Editor editor = prefs.edit();
+// editor.putBoolean(PreferencesActivity.KEY_FRONT_LIGHT, newSetting);
+// editor.commit();
+// }
+ }
+
+ private static void initializeTorch(Camera.Parameters parameters, SharedPreferences prefs) {
+ boolean currentSetting = false;// prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false);
+ doSetTorch(parameters, currentSetting);
+ }
+
+ private static void doSetTorch(Camera.Parameters parameters, boolean newSetting) {
+ String flashMode;
+ if (newSetting) {
+ flashMode = findSettableValue(parameters.getSupportedFlashModes(),
+ Camera.Parameters.FLASH_MODE_TORCH,
+ Camera.Parameters.FLASH_MODE_ON);
+ } else {
+ flashMode = findSettableValue(parameters.getSupportedFlashModes(),
+ Camera.Parameters.FLASH_MODE_OFF);
+ }
+ if (flashMode != null) {
+ parameters.setFlashMode(flashMode);
+ }
+ }
+
+ private static Point findBestPreviewSizeValue(Camera.Parameters parameters,
+ Point screenResolution,
+ boolean portrait) {
+ Point bestSize = null;
+ int diff = Integer.MAX_VALUE;
+ for (Camera.Size supportedPreviewSize : parameters.getSupportedPreviewSizes()) {
+ int pixels = supportedPreviewSize.height * supportedPreviewSize.width;
+ if (pixels < MIN_PREVIEW_PIXELS || pixels > MAX_PREVIEW_PIXELS) {
+ continue;
+ }
+ int supportedWidth = portrait ? supportedPreviewSize.height : supportedPreviewSize.width;
+ int supportedHeight = portrait ? supportedPreviewSize.width : supportedPreviewSize.height;
+ int newDiff = Math.abs(screenResolution.x * supportedHeight - supportedWidth * screenResolution.y);
+ if (newDiff == 0) {
+ bestSize = new Point(supportedWidth, supportedHeight);
+ break;
+ }
+ if (newDiff < diff) {
+ bestSize = new Point(supportedWidth, supportedHeight);
+ diff = newDiff;
+ }
+ }
+ if (bestSize == null) {
+ Camera.Size defaultSize = parameters.getPreviewSize();
+ bestSize = new Point(defaultSize.width, defaultSize.height);
+ }
+ return bestSize;
+ }
+
+ private static String findSettableValue(Collection<String> supportedValues,
+ String... desiredValues) {
+ Log.i(TAG, "Supported values: " + supportedValues);
+ String result = null;
+ if (supportedValues != null) {
+ for (String desiredValue : desiredValues) {
+ if (supportedValues.contains(desiredValue)) {
+ result = desiredValue;
+ break;
+ }
+ }
+ }
+ Log.i(TAG, "Settable value: " + result);
+ return result;
+ }
+
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/camera/CameraManager.java b/qr_scanner/src/com/google/zxing/client/android/camera/CameraManager.java
new file mode 100755
index 0000000..4df7cb1
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/camera/CameraManager.java
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android.camera;
+
+import com.google.zxing.client.android.PlanarYUVLuminanceSource;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.Camera;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+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)
+ */
+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 = 600;
+ private static final int MAX_FRAME_HEIGHT = 400;
+
+ private final Context context;
+ private final CameraConfigurationManager configManager;
+ private Camera camera;
+ private Rect framingRect;
+ private Rect framingRectInPreview;
+ private boolean initialized;
+ private boolean previewing;
+ private boolean reverseImage;
+ 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;
+ /** Autofocus callbacks arrive here, and are dispatched to the Handler which requested them. */
+ private final AutoFocusCallback autoFocusCallback;
+
+ public CameraManager(Context context) {
+ this.context = context;
+ this.configManager = new CameraConfigurationManager(context);
+ previewCallback = new PreviewCallback(configManager);
+ autoFocusCallback = new AutoFocusCallback();
+ }
+
+ /**
+ * 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 void openDriver(SurfaceHolder holder) throws IOException {
+ Camera theCamera = camera;
+ if (theCamera == null) {
+ theCamera = Camera.open();
+ if (theCamera == null) {
+ throw new IOException();
+ }
+ camera = theCamera;
+ }
+ theCamera.setPreviewDisplay(holder);
+
+ if (!initialized) {
+ initialized = true;
+ configManager.initFromCameraParameters(theCamera);
+ if (requestedFramingRectWidth > 0 && requestedFramingRectHeight > 0) {
+ setManualFramingRect(requestedFramingRectWidth, requestedFramingRectHeight);
+ requestedFramingRectWidth = 0;
+ requestedFramingRectHeight = 0;
+ }
+ }
+ configManager.setDesiredCameraParameters(theCamera);
+
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ reverseImage = false;
+ }
+
+ /**
+ * Closes the camera driver if still in use.
+ */
+ public void closeDriver() {
+ if (camera != null) {
+ camera.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 void startPreview() {
+ Camera theCamera = camera;
+ if (theCamera != null && !previewing) {
+ theCamera.startPreview();
+ previewing = true;
+ }
+ }
+
+ /**
+ * Tells the camera to stop drawing preview frames.
+ */
+ public void stopPreview() {
+ if (camera != null && previewing) {
+ camera.stopPreview();
+ previewCallback.setHandler(null, 0);
+ autoFocusCallback.setHandler(null, 0);
+ previewing = false;
+ }
+ }
+
+ /**
+ * 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 void requestPreviewFrame(Handler handler, int message) {
+ Camera theCamera = camera;
+ if (theCamera != null && previewing) {
+ previewCallback.setHandler(handler, message);
+ theCamera.setOneShotPreviewCallback(previewCallback);
+ }
+ }
+
+ /**
+ * Asks the camera hardware to perform an autofocus.
+ *
+ * @param handler The Handler to notify when the autofocus completes.
+ * @param message The message to deliver.
+ */
+ public void requestAutoFocus(Handler handler, int message) {
+ if (camera != null && previewing) {
+ autoFocusCallback.setHandler(handler, message);
+ camera.autoFocus(autoFocusCallback);
+ }
+ }
+
+ /**
+ * 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 Rect getFramingRect() {
+ if (framingRect == null) {
+ if (camera == null) {
+ return null;
+ }
+ Point screenResolution = configManager.getScreenResolution();
+ int width = screenResolution.x * 3 / 4;
+ if (width < MIN_FRAME_WIDTH) {
+ width = MIN_FRAME_WIDTH;
+ } else if (width > MAX_FRAME_WIDTH) {
+ width = MAX_FRAME_WIDTH;
+ }
+ int height = screenResolution.y * 3 / 4;
+ if (height < MIN_FRAME_HEIGHT) {
+ height = MIN_FRAME_HEIGHT;
+ } else if (height > MAX_FRAME_HEIGHT) {
+ 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;
+ }
+
+ /**
+ * Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
+ * not UI / screen.
+ */
+ public Rect getFramingRectInPreview() {
+ if (framingRectInPreview == null) {
+ Rect framingRect = getFramingRect();
+ if (framingRect == null) {
+ return null;
+ }
+ Rect rect = new Rect(framingRect);
+ Point cameraResolution = configManager.getCameraResolution();
+ if (cameraResolution == null) {
+ return framingRect;
+ }
+ Point screenResolution = configManager.getScreenResolution();
+ 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 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 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(), reverseImage);
+ }
+
+}
diff --git a/qr_scanner/src/com/google/zxing/client/android/camera/PreviewCallback.java b/qr_scanner/src/com/google/zxing/client/android/camera/PreviewCallback.java
new file mode 100644
index 0000000..4a75cfe
--- /dev/null
+++ b/qr_scanner/src/com/google/zxing/client/android/camera/PreviewCallback.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package com.google.zxing.client.android.camera;
+
+import android.graphics.Point;
+import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+final class PreviewCallback implements Camera.PreviewCallback {
+
+ private static final String TAG = PreviewCallback.class.getSimpleName();
+
+ private final CameraConfigurationManager configManager;
+ private Handler previewHandler;
+ private int previewMessage;
+
+ PreviewCallback(CameraConfigurationManager configManager) {
+ this.configManager = configManager;
+ }
+
+ void setHandler(Handler previewHandler, int previewMessage) {
+ this.previewHandler = previewHandler;
+ this.previewMessage = previewMessage;
+ }
+
+ public void onPreviewFrame(byte[] data, Camera camera) {
+ Point cameraResolution = configManager.getCameraResolution();
+ Handler thePreviewHandler = previewHandler;
+ if (thePreviewHandler != null) {
+ Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
+ cameraResolution.y, data);
+ message.sendToTarget();
+ previewHandler = null;
+ } else {
+ Log.d(TAG, "Got preview callback, but no handler for it");
+ }
+ }
+
+}