diff --git a/About.md b/About.md
new file mode 100644
index 0000000..c5cb874
--- /dev/null
+++ b/About.md
@@ -0,0 +1,3 @@
+The author -- Hai Bison -- is available for work at [oDesk](https://www.odesk.com/users/~012e482afb87d7637c) or [Elance](https://www.elance.com/s/haibison/).
+
+He's a little funny and hard working :-)
\ No newline at end of file
diff --git a/AdvancedOptions.md b/AdvancedOptions.md
new file mode 100644
index 0000000..b2784ba
--- /dev/null
+++ b/AdvancedOptions.md
@@ -0,0 +1,24 @@
+## Minimum Wired Dots ##
+
+By default, minimum wired dots required are `4`. You can configure that limit with helper class [Settings.Display](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/util/Settings.Display.html), the valid value is in range `1`-`9`. For example, to change it to `3`:
+
+```
+import com.haibison.android.lockpattern.util.Settings;
+
+...
+
+Settings.Display.setMinWiredDots(your-context, 3);
+```
+
+
+## Maximum Retries ##
+
+By default, in comparing pattern mode, maximum retries allowed are `5`. For example, to change it to `3`:
+
+```
+Settings.Display.setMaxRetries(your-context, 3);
+```
+
+## Delivering result to a [PendingIntent](http://developer.android.com/reference/android/app/PendingIntent.html) or [ResultReceiver](http://developer.android.com/reference/android/os/ResultReceiver.html) ##
+
+You can put a `PendingIntent` to [EXTRA\_PENDING\_INTENT\_OK](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html#EXTRA_PENDING_INTENT_OK) or [EXTRA\_PENDING\_INTENT\_CANCELLED](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html#EXTRA_PENDING_INTENT_CANCELLED). The library will call that intent according to the result. Also, to deliver the result to a `ResultReceiver`, you can use key [EXTRA\_RESULT\_RECEIVER](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html#EXTRA_RESULT_RECEIVER).
\ No newline at end of file
diff --git a/AndroidManifest.md b/AndroidManifest.md
new file mode 100644
index 0000000..e16bcce
--- /dev/null
+++ b/AndroidManifest.md
@@ -0,0 +1,25 @@
+All configurations with helper class [Settings](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/util/Settings.html) (and all of its nested classes) must be called before you start [LockPatternActivity](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html). But you _can_ configure settings in an activity and call `LockPatternActivity` in another activity.
+
+However that could make the usage more complicated. So there's an option: You can also configure settings directly via your app's `AndroidManifest.xml`. For details, refer to class `Settings`. Note that the values in the manifest get higher priority than the ones from this class.
+
+For example, this is used in the demo app:
+
+```
+
+
+
+
+```
+
+If you use ProGuard _and_ set your encrypter class via manifest like above, remember to ignore your encrypter class:
+```
+-keep class group.pals.android.lib.ui.lockpattern.demo.LPEncrypter { *; }
+```
\ No newline at end of file
diff --git a/AppsOnGooglePlay.md b/AppsOnGooglePlay.md
new file mode 100644
index 0000000..76b148d
--- /dev/null
+++ b/AppsOnGooglePlay.md
@@ -0,0 +1,12 @@
+
+
+<hr>
+
+
+
+If you have apps on Google Play which use this library, and you would like to show your apps here, please send us an email.
+
+### Notes ###
+
+ * The apps are listed in order of notification to us.
+ * Please include the link to its home on Google Play.
\ No newline at end of file
diff --git a/Credits.md b/Credits.md
new file mode 100644
index 0000000..5596770
--- /dev/null
+++ b/Credits.md
@@ -0,0 +1,7 @@
+We sincerely thank all of our friends — who have been contributing to this project. We hope this project will be always useful for everyone.
+
+ * C
+ * [Steven Byle](http://stackoverflow.com/users/1507439/steven-byle)
+ * Thomas Breitbach
+ * Yan Cheng Cheok (Project Admin of [JStock](http://jstock.sourceforge.net/))
+ * And others.
\ No newline at end of file
diff --git a/Encryption.md b/Encryption.md
new file mode 100644
index 0000000..938f8fd
--- /dev/null
+++ b/Encryption.md
@@ -0,0 +1,72 @@
+It will be more secure if for each app, you have a unique encrypter — to encrypt the pattern on your own way.
+
+# Details #
+
+For example, here is a simple encrypter (which is used in the demo app), we name it `LPEncrypter`:
+```
+package ...
+
+import com.haibison.android.lockpattern.collect.Lists;
+import com.haibison.android.lockpattern.util.IEncrypter;
+import com.haibison.android.lockpattern.widget.LockPatternView.Cell;
+
+import java.util.List;
+
+import android.content.Context;
+
+public class LPEncrypter implements IEncrypter {
+
+ @Override
+ public char[] encrypt(Context context, List pattern) {
+ /*
+ * This is a simple example. And it's also worth mentioning that this is
+ * a very weak encrypter, just for fun :-)
+ */
+
+ StringBuilder result = new StringBuilder();
+ for (Cell cell : pattern)
+ result.append(Integer.toString(cell.getId() + 1)).append('-');
+
+ return result.substring(0, result.length() - 1).toCharArray();
+ }// encrypt()
+
+ @Override
+ public List decrypt(Context context, char[] encryptedPattern) {
+ List result = Lists.newArrayList();
+ String[] ids = new String(encryptedPattern).split("[^0-9]");
+ for (String id : ids)
+ result.add(Cell.of(Integer.parseInt(id) - 1));
+
+ return result;
+ }// decrypt()
+
+}
+```
+
+Usage:
+```
+import com.haibison.android.lockpattern.util.Settings;
+
+...
+
+Settings.Security.setEncrypterClass(your-context, LPEncrypter.class);
+```
+
+Or via [AndroidManifest.xml](AndroidManifest.md):
+```
+
+
+
+```
+
+You might want to take a look at built-in class [SimpleWeakEncryption](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/util/SimpleWeakEncryption.html). However, like its name suggests, it is just a _simple and weak_ encryption utility. Use it on your own risk :-)
+
+# Notes #
+
+ * Classes implementing [IEncrypter](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/util/IEncrypter.html) must have one zero-argument constructor. Otherwise, an [InvalidEncrypterException](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/util/InvalidEncrypterException.html) will be thrown.
\ No newline at end of file
diff --git a/FAQs.md b/FAQs.md
new file mode 100644
index 0000000..f66da91
--- /dev/null
+++ b/FAQs.md
@@ -0,0 +1,13 @@
+### I'm new, where should I start? ###
+
+Please, have a look at [Quick Use](QuickUse.md).
+
+### Why resources are named with prefix `alp_42447968_`? ###
+
+To avoid of collisions of resources with other libraries, or with the host project. At first we've tried `alp_`, but to make it safer, we've added a CRC-32 string `42447968_`. A CRC-32 string is shorter than an MD-5 string, and we think that would be safe enough.
+
+### Where are preferences/settings saved? ###
+
+On app's internal storage. Preferences files are named with suffix `a6eedbe5-1cf9-4684-8134-ad4ec9f6a131` (constant [Sys.UID](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/util/Sys.html#UID)). And for your information, `42447968` is CRC-32 of above suffix.
+
+And of course, the library's preferences don't mess with your app's own preferences, or other libraries' preferences.
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 2a1bef4..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- 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/LockPatternViewTest/.classpath b/LockPatternViewTest/.classpath
deleted file mode 100644
index 7bc01d9..0000000
--- a/LockPatternViewTest/.classpath
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/LockPatternViewTest/.project b/LockPatternViewTest/.project
deleted file mode 100644
index 80f24df..0000000
--- a/LockPatternViewTest/.project
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
- LockPatternViewTest
-
-
-
-
-
- com.android.ide.eclipse.adt.ResourceManagerBuilder
-
-
-
-
- com.android.ide.eclipse.adt.PreCompilerBuilder
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- com.android.ide.eclipse.adt.ApkBuilder
-
-
-
-
-
- com.android.ide.eclipse.adt.AndroidNature
- org.eclipse.jdt.core.javanature
-
-
diff --git a/LockPatternViewTest/AndroidManifest.xml b/LockPatternViewTest/AndroidManifest.xml
deleted file mode 100644
index 6385e72..0000000
--- a/LockPatternViewTest/AndroidManifest.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/LockPatternViewTest/build.xml b/LockPatternViewTest/build.xml
deleted file mode 100644
index c8cb426..0000000
--- a/LockPatternViewTest/build.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/LockPatternViewTest/proguard-project.txt b/LockPatternViewTest/proguard-project.txt
deleted file mode 100644
index f2fe155..0000000
--- a/LockPatternViewTest/proguard-project.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/LockPatternViewTest/project.properties b/LockPatternViewTest/project.properties
deleted file mode 100644
index 6e18427..0000000
--- a/LockPatternViewTest/project.properties
+++ /dev/null
@@ -1,14 +0,0 @@
-# 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 edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-target=android-21
diff --git a/LockPatternViewTest/res/drawable-hdpi/ic_launcher.png b/LockPatternViewTest/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 96a442e..0000000
Binary files a/LockPatternViewTest/res/drawable-hdpi/ic_launcher.png and /dev/null differ
diff --git a/LockPatternViewTest/res/drawable-mdpi/ic_launcher.png b/LockPatternViewTest/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 359047d..0000000
Binary files a/LockPatternViewTest/res/drawable-mdpi/ic_launcher.png and /dev/null differ
diff --git a/LockPatternViewTest/res/drawable-xhdpi/ic_launcher.png b/LockPatternViewTest/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 71c6d76..0000000
Binary files a/LockPatternViewTest/res/drawable-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/LockPatternViewTest/res/values-v11/styles.xml b/LockPatternViewTest/res/values-v11/styles.xml
deleted file mode 100644
index b1d0383..0000000
--- a/LockPatternViewTest/res/values-v11/styles.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/LockPatternViewTest/res/values-v21/styles.xml b/LockPatternViewTest/res/values-v21/styles.xml
deleted file mode 100644
index b471c82..0000000
--- a/LockPatternViewTest/res/values-v21/styles.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/LockPatternViewTest/res/values/colors.xml b/LockPatternViewTest/res/values/colors.xml
deleted file mode 100644
index 8f1e4ff..0000000
--- a/LockPatternViewTest/res/values/colors.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
- #ffffffff
- #ffffffff
- #fff4511e
- #ff37474f
- #ff009688
- #fff4511e
-
-
\ No newline at end of file
diff --git a/LockPatternViewTest/res/values/dimens.xml b/LockPatternViewTest/res/values/dimens.xml
deleted file mode 100644
index 3bba14a..0000000
--- a/LockPatternViewTest/res/values/dimens.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
- 3dp
- 12dp
- 28dp
-
-
\ No newline at end of file
diff --git a/LockPatternViewTest/res/values/strings.xml b/LockPatternViewTest/res/values/strings.xml
deleted file mode 100644
index 4425e25..0000000
--- a/LockPatternViewTest/res/values/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
- LockPatternView Test
-
-
- Pattern started
-
- Pattern cleared
-
- Cell added
-
- Pattern completed
-
-
\ No newline at end of file
diff --git a/LockPatternViewTest/res/values/styles.xml b/LockPatternViewTest/res/values/styles.xml
deleted file mode 100644
index f1699ff..0000000
--- a/LockPatternViewTest/res/values/styles.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/LockPatternViewTest/src/app/MainActivity.java b/LockPatternViewTest/src/app/MainActivity.java
deleted file mode 100644
index 7319c1b..0000000
--- a/LockPatternViewTest/src/app/MainActivity.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 app;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-import com.android.internal.widget.LockPatternViewEx;
-
-/**
- * Main activity.
- *
- * @author Hai Bison
- *
- */
-public class MainActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(new LockPatternViewEx(this));
- }// onCreate()
-
-}
diff --git a/LockPatternViewTest/src/app/utils/Resources.java b/LockPatternViewTest/src/app/utils/Resources.java
deleted file mode 100644
index c4fbd6c..0000000
--- a/LockPatternViewTest/src/app/utils/Resources.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 app.utils;
-
-import android.content.Context;
-import android.util.TypedValue;
-
-/**
- * Resources' utilities.
- *
- * @author Hai Bison
- *
- */
-public class Resources {
-
- /**
- * This is singleton class.
- */
- private Resources() {
- }// Resources()
-
- /**
- * Convenient method for {@link Context#getTheme()} and
- * {@link Resources.Theme#resolveAttribute(int, TypedValue, boolean)}.
- *
- * @param context
- * the context.
- * @param resId
- * The resource identifier of the desired theme attribute.
- * @return the resource ID that {@link TypedValue#resourceId} points to, or
- * {@code 0} if not found.
- */
- public static int resolveAttribute(Context context, int resId) {
- return resolveAttribute(context, resId, 0);
- }// resolveAttribute()
-
- /**
- * Convenient method for {@link Context#getTheme()} and
- * {@link Resources.Theme#resolveAttribute(int, TypedValue, boolean)}.
- *
- * @param context
- * the context.
- * @param resId
- * The resource identifier of the desired theme attribute.
- * @param defaultValue
- * the default value if cannot resolve {@code resId}.
- * @return the resource ID that {@link TypedValue#resourceId} points to, or
- * {@code defaultValue} if not found.
- */
- public static int resolveAttribute(Context context, int resId,
- int defaultValue) {
- TypedValue typedValue = new TypedValue();
- if (context.getTheme().resolveAttribute(resId, typedValue, true))
- return typedValue.resourceId;
- return defaultValue;
- }// resolveAttribute()
-
-}
diff --git a/LockPatternViewTest/src/com/android/internal/widget/LockPatternUtils.java b/LockPatternViewTest/src/com/android/internal/widget/LockPatternUtils.java
deleted file mode 100644
index f131981..0000000
--- a/LockPatternViewTest/src/com/android/internal/widget/LockPatternUtils.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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.android.internal.widget;
-
-import java.util.List;
-
-import com.google.android.collect.Lists;
-
-/**
- * Utilities for the lock pattern and its settings.
- */
-public class LockPatternUtils {
-
- /**
- * Deserialize a pattern.
- *
- * @param string
- * The pattern serialized with {@link #patternToString}
- * @return The pattern.
- */
- public static List stringToPattern(String string) {
- List result = Lists.newArrayList();
-
- final byte[] bytes = string.getBytes();
- for (int i = 0; i < bytes.length; i++) {
- byte b = bytes[i];
- result.add(LockPatternViewEx.Cell.of(b / 3, b % 3));
- }
- return result;
- }
-
- /**
- * Serialize a pattern.
- *
- * @param pattern
- * The pattern.
- * @return The pattern in string form.
- */
- public static String patternToString(List pattern) {
- if (pattern == null) {
- return "";
- }
- final int patternSize = pattern.size();
-
- byte[] res = new byte[patternSize];
- for (int i = 0; i < patternSize; i++) {
- LockPatternViewEx.Cell cell = pattern.get(i);
- res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
- }
- return new String(res);
- }
-
-}
diff --git a/LockPatternViewTest/src/com/android/internal/widget/LockPatternViewEx.java b/LockPatternViewTest/src/com/android/internal/widget/LockPatternViewEx.java
deleted file mode 100644
index 0b5c67f..0000000
--- a/LockPatternViewTest/src/com/android/internal/widget/LockPatternViewEx.java
+++ /dev/null
@@ -1,1204 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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.android.internal.widget;
-
-import haibison.test.lockpatternview.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.Debug;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.view.HapticFeedbackConstants;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import app.utils.Resources;
-
-/**
- * Displays and detects the user's unlock attempt, which is a drag of a finger
- * across 9 regions of the screen.
- *
- * Is also capable of displaying a static pattern in "in progress", "wrong" or
- * "correct" states.
- */
-public class LockPatternViewEx extends View {
-
- // Aspect to use when rendering this view
- private static final int ASPECT_SQUARE = 0; // View will be the minimum of
- // width/height
- private static final int ASPECT_LOCK_WIDTH = 1; // Fixed width; height will
- // be minimum of (w,h)
- private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will
- // be minimum of (w,h)
-
- private static final boolean PROFILE_DRAWING = false;
- private final CellState[][] mCellStates;
-
- private final int mDotSize;
- private final int mDotSizeActivated;
- private final int mPathWidth;
-
- private boolean mDrawingProfilingStarted = false;
-
- private Paint mPaint = new Paint();
- private Paint mPathPaint = new Paint();
-
- /**
- * How many milliseconds we spend animating each circle of a lock pattern if
- * the animating mode is set. The entire animation should take this constant
- * * the length of the pattern to complete.
- */
- private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
-
- /**
- * This can be used to avoid updating the display for very small motions or
- * noisy panels. It didn't seem to have much impact on the devices tested,
- * so currently set to 0.
- */
- private static final float DRAG_THRESHHOLD = 0.0f;
-
- private OnPatternListener mOnPatternListener;
- private ArrayList mPattern = new ArrayList(9);
-
- /**
- * Lookup table for the circles of the pattern we are currently drawing.
- * This will be the cells of the complete pattern unless we are animating,
- * in which case we use this to hold the cells we are drawing for the in
- * progress animation.
- */
- private boolean[][] mPatternDrawLookup = new boolean[3][3];
-
- /**
- * the in progress point: - during interaction: where the user's finger is -
- * during animation: the current tip of the animating line
- */
- private float mInProgressX = -1;
- private float mInProgressY = -1;
-
- private long mAnimatingPeriodStart;
-
- private DisplayMode mPatternDisplayMode = DisplayMode.Correct;
- private boolean mInputEnabled = true;
- private boolean mInStealthMode = false;
- private boolean mEnableHapticFeedback = true;
- private boolean mPatternInProgress = false;
-
- private float mHitFactor = 0.6f;
-
- private float mSquareWidth;
- private float mSquareHeight;
-
- private final Path mCurrentPath = new Path();
- private final Rect mInvalidate = new Rect();
- private final Rect mTmpInvalidateRect = new Rect();
-
- private int mAspect;
- private int mRegularColor;
- private int mErrorColor;
- private int mSuccessColor;
-
- private Interpolator mFastOutSlowInInterpolator;
- private Interpolator mLinearOutSlowInInterpolator;
-
- /**
- * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
- */
- public static class Cell {
-
- int row;
- int column;
-
- // keep # objects limited to 9
- static Cell[][] sCells = new Cell[3][3];
- static {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- sCells[i][j] = new Cell(i, j);
- }
- }
- }
-
- /**
- * @param row
- * The row of the cell.
- * @param column
- * The column of the cell.
- */
- private Cell(int row, int column) {
- checkRange(row, column);
- this.row = row;
- this.column = column;
- }
-
- public int getRow() {
- return row;
- }
-
- public int getColumn() {
- return column;
- }
-
- /**
- * @param row
- * The row of the cell.
- * @param column
- * The column of the cell.
- */
- public static synchronized Cell of(int row, int column) {
- checkRange(row, column);
- return sCells[row][column];
- }
-
- private static void checkRange(int row, int column) {
- if (row < 0 || row > 2) {
- throw new IllegalArgumentException("row must be in range 0-2");
- }
- if (column < 0 || column > 2) {
- throw new IllegalArgumentException(
- "column must be in range 0-2");
- }
- }
-
- public String toString() {
- return "(row=" + row + ",clmn=" + column + ")";
- }
- }
-
- public static class CellState {
-
- public float scale = 1.0f;
- public float translateY = 0.0f;
- public float alpha = 1.0f;
- public float size;
- public float lineEndX = Float.MIN_VALUE;
- public float lineEndY = Float.MIN_VALUE;
- public ValueAnimator lineAnimator;
- }
-
- /**
- * How to display the current pattern.
- */
- public enum DisplayMode {
-
- /**
- * The pattern drawn is correct (i.e draw it in a friendly color)
- */
- Correct,
-
- /**
- * Animate the pattern (for demo, and help).
- */
- Animate,
-
- /**
- * The pattern is wrong (i.e draw a foreboding color)
- */
- Wrong
- }
-
- /**
- * The call back interface for detecting patterns entered by the user.
- */
- public static interface OnPatternListener {
-
- /**
- * A new pattern has begun.
- */
- void onPatternStart();
-
- /**
- * The pattern was cleared.
- */
- void onPatternCleared();
-
- /**
- * The user extended the pattern currently being drawn by one cell.
- *
- * @param pattern
- * The pattern with newly added cell.
- */
- void onPatternCellAdded(List pattern);
-
- /**
- * A pattern was detected from the user.
- *
- * @param pattern
- * The pattern.
- */
- void onPatternDetected(List pattern);
- }
-
- public LockPatternViewEx(Context context) {
- this(context, null);
- }
-
- public LockPatternViewEx(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.LockPatternViewEx);
-
- final String aspect = a.getString(R.styleable.LockPatternViewEx_aspect);
-
- if ("square".equals(aspect)) {
- mAspect = ASPECT_SQUARE;
- } else if ("lock_width".equals(aspect)) {
- mAspect = ASPECT_LOCK_WIDTH;
- } else if ("lock_height".equals(aspect)) {
- mAspect = ASPECT_LOCK_HEIGHT;
- } else {
- mAspect = ASPECT_SQUARE;
- }
-
- setClickable(true);
-
- mPathPaint.setAntiAlias(true);
- mPathPaint.setDither(true);
-
- mRegularColor = getResources().getColor(
- Resources.resolveAttribute(getContext(),
- R.attr.color_lock_pattern_view_regular));
- mErrorColor = getResources().getColor(
- Resources.resolveAttribute(getContext(),
- R.attr.color_lock_pattern_view_error));
- mSuccessColor = getResources().getColor(
- Resources.resolveAttribute(getContext(),
- R.attr.color_lock_pattern_view_success));
-
- mRegularColor = a.getColor(R.styleable.LockPatternViewEx_regularColor,
- mRegularColor);
- mErrorColor = a.getColor(R.styleable.LockPatternViewEx_errorColor,
- mErrorColor);
- mSuccessColor = a.getColor(R.styleable.LockPatternViewEx_successColor,
- mSuccessColor);
-
- int pathColor = a.getColor(R.styleable.LockPatternViewEx_pathColor,
- mRegularColor);
- mPathPaint.setColor(pathColor);
-
- mPathPaint.setStyle(Paint.Style.STROKE);
- mPathPaint.setStrokeJoin(Paint.Join.ROUND);
- mPathPaint.setStrokeCap(Paint.Cap.ROUND);
-
- mPathWidth = getResources().getDimensionPixelSize(
- R.dimen.lock_pattern_dot_line_width);
- mPathPaint.setStrokeWidth(mPathWidth);
-
- mDotSize = getResources().getDimensionPixelSize(
- R.dimen.lock_pattern_dot_size);
- mDotSizeActivated = getResources().getDimensionPixelSize(
- R.dimen.lock_pattern_dot_size_activated);
-
- mPaint.setAntiAlias(true);
- mPaint.setDither(true);
-
- mCellStates = new CellState[3][3];
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- mCellStates[i][j] = new CellState();
- mCellStates[i][j].size = mDotSize;
- }
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- context, android.R.interpolator.fast_out_slow_in);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- context, android.R.interpolator.linear_out_slow_in);
- }// if
- }
-
- public CellState[][] getCellStates() {
- return mCellStates;
- }
-
- /**
- * @return Whether the view is in stealth mode.
- */
- public boolean isInStealthMode() {
- return mInStealthMode;
- }
-
- /**
- * @return Whether the view has tactile feedback enabled.
- */
- public boolean isTactileFeedbackEnabled() {
- return mEnableHapticFeedback;
- }
-
- /**
- * Set whether the view is in stealth mode. If true, there will be no
- * visible feedback as the user enters the pattern.
- *
- * @param inStealthMode
- * Whether in stealth mode.
- */
- public void setInStealthMode(boolean inStealthMode) {
- mInStealthMode = inStealthMode;
- }
-
- /**
- * Set whether the view will use tactile feedback. If true, there will be
- * tactile feedback as the user enters the pattern.
- *
- * @param tactileFeedbackEnabled
- * Whether tactile feedback is enabled
- */
- public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) {
- mEnableHapticFeedback = tactileFeedbackEnabled;
- }
-
- /**
- * Set the call back for pattern detection.
- *
- * @param onPatternListener
- * The call back.
- */
- public void setOnPatternListener(OnPatternListener onPatternListener) {
- mOnPatternListener = onPatternListener;
- }
-
- /**
- * Set the pattern explicitely (rather than waiting for the user to input a
- * pattern).
- *
- * @param displayMode
- * How to display the pattern.
- * @param pattern
- * The pattern.
- */
- public void setPattern(DisplayMode displayMode, List pattern) {
- mPattern.clear();
- mPattern.addAll(pattern);
- clearPatternDrawLookup();
- for (Cell cell : pattern) {
- mPatternDrawLookup[cell.getRow()][cell.getColumn()] = true;
- }
-
- setDisplayMode(displayMode);
- }
-
- /**
- * Set the display mode of the current pattern. This can be useful, for
- * instance, after detecting a pattern to tell this view whether change the
- * in progress result to correct or wrong.
- *
- * @param displayMode
- * The display mode.
- */
- public void setDisplayMode(DisplayMode displayMode) {
- mPatternDisplayMode = displayMode;
- if (displayMode == DisplayMode.Animate) {
- if (mPattern.size() == 0) {
- throw new IllegalStateException(
- "you must have a pattern to "
- + "animate if you want to set the display mode to animate");
- }
- mAnimatingPeriodStart = SystemClock.elapsedRealtime();
- final Cell first = mPattern.get(0);
- mInProgressX = getCenterXForColumn(first.getColumn());
- mInProgressY = getCenterYForRow(first.getRow());
- clearPatternDrawLookup();
- }
- invalidate();
- }
-
- private void notifyCellAdded() {
- sendAccessEvent(R.string.lockscreen_access_pattern_cell_added);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternCellAdded(mPattern);
- }
- }
-
- private void notifyPatternStarted() {
- sendAccessEvent(R.string.lockscreen_access_pattern_start);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternStart();
- }
- }
-
- private void notifyPatternDetected() {
- sendAccessEvent(R.string.lockscreen_access_pattern_detected);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternDetected(mPattern);
- }
- }
-
- private void notifyPatternCleared() {
- sendAccessEvent(R.string.lockscreen_access_pattern_cleared);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternCleared();
- }
- }
-
- /**
- * Clear the pattern.
- */
- public void clearPattern() {
- resetPattern();
- }
-
- /**
- * Reset all pattern state.
- */
- private void resetPattern() {
- mPattern.clear();
- clearPatternDrawLookup();
- mPatternDisplayMode = DisplayMode.Correct;
- invalidate();
- }
-
- /**
- * Clear the pattern lookup table.
- */
- private void clearPatternDrawLookup() {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- mPatternDrawLookup[i][j] = false;
- }
- }
- }
-
- /**
- * Disable input (for instance when displaying a message that will timeout
- * so user doesn't get view into messy state).
- */
- public void disableInput() {
- mInputEnabled = false;
- }
-
- /**
- * Enable input.
- */
- public void enableInput() {
- mInputEnabled = true;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- final int width = w - getPaddingLeft() - getPaddingRight();
- mSquareWidth = width / 3.0f;
-
- final int height = h - getPaddingTop() - getPaddingBottom();
- mSquareHeight = height / 3.0f;
- }
-
- private int resolveMeasured(int measureSpec, int desired) {
- int result = 0;
- int specSize = MeasureSpec.getSize(measureSpec);
- switch (MeasureSpec.getMode(measureSpec)) {
- case MeasureSpec.UNSPECIFIED:
- result = desired;
- break;
- case MeasureSpec.AT_MOST:
- result = Math.max(specSize, desired);
- break;
- case MeasureSpec.EXACTLY:
- default:
- result = specSize;
- }
- return result;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int minimumWidth = getSuggestedMinimumWidth();
- final int minimumHeight = getSuggestedMinimumHeight();
- int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
- int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
-
- switch (mAspect) {
- case ASPECT_SQUARE:
- viewWidth = viewHeight = Math.min(viewWidth, viewHeight);
- break;
- case ASPECT_LOCK_WIDTH:
- viewHeight = Math.min(viewWidth, viewHeight);
- break;
- case ASPECT_LOCK_HEIGHT:
- viewWidth = Math.min(viewWidth, viewHeight);
- break;
- }
- // Log.v(TAG, "LockPatternView dimensions: " + viewWidth + "x" +
- // viewHeight);
- setMeasuredDimension(viewWidth, viewHeight);
- }
-
- /**
- * Determines whether the point x, y will add a new point to the current
- * pattern (in addition to finding the cell, also makes heuristic choices
- * such as filling in gaps based on current pattern).
- *
- * @param x
- * The x coordinate.
- * @param y
- * The y coordinate.
- */
- private Cell detectAndAddHit(float x, float y) {
- final Cell cell = checkForNewHit(x, y);
- if (cell != null) {
-
- // check for gaps in existing pattern
- Cell fillInGapCell = null;
- final ArrayList pattern = mPattern;
- if (!pattern.isEmpty()) {
- final Cell lastCell = pattern.get(pattern.size() - 1);
- int dRow = cell.row - lastCell.row;
- int dColumn = cell.column - lastCell.column;
-
- int fillInRow = lastCell.row;
- int fillInColumn = lastCell.column;
-
- if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) {
- fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1);
- }
-
- if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) {
- fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1);
- }
-
- fillInGapCell = Cell.of(fillInRow, fillInColumn);
- }
-
- if (fillInGapCell != null
- && !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
- addCellToPattern(fillInGapCell);
- }
- addCellToPattern(cell);
- if (mEnableHapticFeedback) {
- performHapticFeedback(
- HapticFeedbackConstants.VIRTUAL_KEY,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
- | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
- }
- return cell;
- }
- return null;
- }
-
- private void addCellToPattern(Cell newCell) {
- mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true;
- mPattern.add(newCell);
- if (!mInStealthMode) {
- startCellActivatedAnimation(newCell);
- }
- notifyCellAdded();
- }
-
- private void startCellActivatedAnimation(Cell cell) {
- final CellState cellState = mCellStates[cell.row][cell.column];
- startSizeAnimation(mDotSize, mDotSizeActivated, 96,
- mLinearOutSlowInInterpolator, cellState, new Runnable() {
-
- @Override
- public void run() {
- startSizeAnimation(mDotSizeActivated, mDotSize, 192,
- mFastOutSlowInInterpolator, cellState, null);
- }
- });
- startLineEndAnimation(cellState, mInProgressX, mInProgressY,
- getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
- }
-
- private void startLineEndAnimation(final CellState state,
- final float startX, final float startY, final float targetX,
- final float targetY) {
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
- valueAnimator
- .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float t = (Float) animation.getAnimatedValue();
- state.lineEndX = (1 - t) * startX + t * targetX;
- state.lineEndY = (1 - t) * startY + t * targetY;
- invalidate();
- }
- });
- valueAnimator.addListener(new AnimatorListenerAdapter() {
-
- @Override
- public void onAnimationEnd(Animator animation) {
- state.lineAnimator = null;
- }
- });
- valueAnimator.setInterpolator(mFastOutSlowInInterpolator);
- valueAnimator.setDuration(100);
- valueAnimator.start();
- state.lineAnimator = valueAnimator;
- }
-
- private void startSizeAnimation(float start, float end, long duration,
- Interpolator interpolator, final CellState state,
- final Runnable endRunnable) {
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
- valueAnimator
- .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- state.size = (Float) animation.getAnimatedValue();
- invalidate();
- }
- });
- if (endRunnable != null) {
- valueAnimator.addListener(new AnimatorListenerAdapter() {
-
- @Override
- public void onAnimationEnd(Animator animation) {
- endRunnable.run();
- }
- });
- }
- valueAnimator.setInterpolator(interpolator);
- valueAnimator.setDuration(duration);
- valueAnimator.start();
- }
-
- // helper method to find which cell a point maps to
- private Cell checkForNewHit(float x, float y) {
-
- final int rowHit = getRowHit(y);
- if (rowHit < 0) {
- return null;
- }
- final int columnHit = getColumnHit(x);
- if (columnHit < 0) {
- return null;
- }
-
- if (mPatternDrawLookup[rowHit][columnHit]) {
- return null;
- }
- return Cell.of(rowHit, columnHit);
- }
-
- /**
- * Helper method to find the row that y falls into.
- *
- * @param y
- * The y coordinate
- * @return The row that y falls in, or -1 if it falls in no row.
- */
- private int getRowHit(float y) {
-
- final float squareHeight = mSquareHeight;
- float hitSize = squareHeight * mHitFactor;
-
- float offset = getPaddingTop() + (squareHeight - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
-
- final float hitTop = offset + squareHeight * i;
- if (y >= hitTop && y <= hitTop + hitSize) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Helper method to find the column x fallis into.
- *
- * @param x
- * The x coordinate.
- * @return The column that x falls in, or -1 if it falls in no column.
- */
- private int getColumnHit(float x) {
- final float squareWidth = mSquareWidth;
- float hitSize = squareWidth * mHitFactor;
-
- float offset = getPaddingLeft() + (squareWidth - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
-
- final float hitLeft = offset + squareWidth * i;
- if (x >= hitLeft && x <= hitLeft + hitSize) {
- return i;
- }
- }
- return -1;
- }
-
- @Override
- public boolean onHoverEvent(MotionEvent event) {
- if (((AccessibilityManager) getContext().getSystemService(
- Context.ACCESSIBILITY_SERVICE)).isTouchExplorationEnabled()) {
- final int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_HOVER_ENTER:
- event.setAction(MotionEvent.ACTION_DOWN);
- break;
- case MotionEvent.ACTION_HOVER_MOVE:
- event.setAction(MotionEvent.ACTION_MOVE);
- break;
- case MotionEvent.ACTION_HOVER_EXIT:
- event.setAction(MotionEvent.ACTION_UP);
- break;
- }
- onTouchEvent(event);
- event.setAction(action);
- }
- return super.onHoverEvent(event);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!mInputEnabled || !isEnabled()) {
- return false;
- }
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- handleActionDown(event);
- return true;
- case MotionEvent.ACTION_UP:
- handleActionUp(event);
- return true;
- case MotionEvent.ACTION_MOVE:
- handleActionMove(event);
- return true;
- case MotionEvent.ACTION_CANCEL:
- if (mPatternInProgress) {
- mPatternInProgress = false;
- resetPattern();
- notifyPatternCleared();
- }
- if (PROFILE_DRAWING) {
- if (mDrawingProfilingStarted) {
- Debug.stopMethodTracing();
- mDrawingProfilingStarted = false;
- }
- }
- return true;
- }
- return false;
- }
-
- private void handleActionMove(MotionEvent event) {
- // Handle all recent motion events so we don't skip any cells even when
- // the device
- // is busy...
- final float radius = mPathWidth;
- final int historySize = event.getHistorySize();
- mTmpInvalidateRect.setEmpty();
- boolean invalidateNow = false;
- for (int i = 0; i < historySize + 1; i++) {
- final float x = i < historySize ? event.getHistoricalX(i) : event
- .getX();
- final float y = i < historySize ? event.getHistoricalY(i) : event
- .getY();
- Cell hitCell = detectAndAddHit(x, y);
- final int patternSize = mPattern.size();
- if (hitCell != null && patternSize == 1) {
- mPatternInProgress = true;
- notifyPatternStarted();
- }
- // note current x and y for rubber banding of in progress patterns
- final float dx = Math.abs(x - mInProgressX);
- final float dy = Math.abs(y - mInProgressY);
- if (dx > DRAG_THRESHHOLD || dy > DRAG_THRESHHOLD) {
- invalidateNow = true;
- }
-
- if (mPatternInProgress && patternSize > 0) {
- final ArrayList pattern = mPattern;
- final Cell lastCell = pattern.get(patternSize - 1);
- float lastCellCenterX = getCenterXForColumn(lastCell.column);
- float lastCellCenterY = getCenterYForRow(lastCell.row);
-
- // Adjust for drawn segment from last cell to (x,y). Radius
- // accounts for line width.
- float left = Math.min(lastCellCenterX, x) - radius;
- float right = Math.max(lastCellCenterX, x) + radius;
- float top = Math.min(lastCellCenterY, y) - radius;
- float bottom = Math.max(lastCellCenterY, y) + radius;
-
- // Invalidate between the pattern's new cell and the pattern's
- // previous cell
- if (hitCell != null) {
- final float width = mSquareWidth * 0.5f;
- final float height = mSquareHeight * 0.5f;
- final float hitCellCenterX = getCenterXForColumn(hitCell.column);
- final float hitCellCenterY = getCenterYForRow(hitCell.row);
-
- left = Math.min(hitCellCenterX - width, left);
- right = Math.max(hitCellCenterX + width, right);
- top = Math.min(hitCellCenterY - height, top);
- bottom = Math.max(hitCellCenterY + height, bottom);
- }
-
- // Invalidate between the pattern's last cell and the previous
- // location
- mTmpInvalidateRect.union(Math.round(left), Math.round(top),
- Math.round(right), Math.round(bottom));
- }
- }
- mInProgressX = event.getX();
- mInProgressY = event.getY();
-
- // To save updates, we only invalidate if the user moved beyond a
- // certain amount.
- if (invalidateNow) {
- mInvalidate.union(mTmpInvalidateRect);
- invalidate(mInvalidate);
- mInvalidate.set(mTmpInvalidateRect);
- }
- }
-
- private void sendAccessEvent(int resId) {
- announceForAccessibility(getContext().getString(resId));
- }
-
- private void handleActionUp(MotionEvent event) {
- // report pattern detected
- if (!mPattern.isEmpty()) {
- mPatternInProgress = false;
- cancelLineAnimations();
- notifyPatternDetected();
- invalidate();
- }
- if (PROFILE_DRAWING) {
- if (mDrawingProfilingStarted) {
- Debug.stopMethodTracing();
- mDrawingProfilingStarted = false;
- }
- }
- }
-
- private void cancelLineAnimations() {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- CellState state = mCellStates[i][j];
- if (state.lineAnimator != null) {
- state.lineAnimator.cancel();
- state.lineEndX = Float.MIN_VALUE;
- state.lineEndY = Float.MIN_VALUE;
- }
- }
- }
- }
-
- private void handleActionDown(MotionEvent event) {
- resetPattern();
- final float x = event.getX();
- final float y = event.getY();
- final Cell hitCell = detectAndAddHit(x, y);
- if (hitCell != null) {
- mPatternInProgress = true;
- mPatternDisplayMode = DisplayMode.Correct;
- notifyPatternStarted();
- } else if (mPatternInProgress) {
- mPatternInProgress = false;
- notifyPatternCleared();
- }
- if (hitCell != null) {
- final float startX = getCenterXForColumn(hitCell.column);
- final float startY = getCenterYForRow(hitCell.row);
-
- final float widthOffset = mSquareWidth / 2f;
- final float heightOffset = mSquareHeight / 2f;
-
- invalidate((int) (startX - widthOffset),
- (int) (startY - heightOffset),
- (int) (startX + widthOffset), (int) (startY + heightOffset));
- }
- mInProgressX = x;
- mInProgressY = y;
- if (PROFILE_DRAWING) {
- if (!mDrawingProfilingStarted) {
- Debug.startMethodTracing("LockPatternDrawing");
- mDrawingProfilingStarted = true;
- }
- }
- }
-
- private float getCenterXForColumn(int column) {
- return getPaddingLeft() + column * mSquareWidth + mSquareWidth / 2f;
- }
-
- private float getCenterYForRow(int row) {
- return getPaddingTop() + row * mSquareHeight + mSquareHeight / 2f;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- final ArrayList pattern = mPattern;
- final int count = pattern.size();
- final boolean[][] drawLookup = mPatternDrawLookup;
-
- if (mPatternDisplayMode == DisplayMode.Animate) {
-
- // figure out which circles to draw
-
- // + 1 so we pause on complete pattern
- final int oneCycle = (count + 1) * MILLIS_PER_CIRCLE_ANIMATING;
- final int spotInCycle = (int) (SystemClock.elapsedRealtime() - mAnimatingPeriodStart)
- % oneCycle;
- final int numCircles = spotInCycle / MILLIS_PER_CIRCLE_ANIMATING;
-
- clearPatternDrawLookup();
- for (int i = 0; i < numCircles; i++) {
- final Cell cell = pattern.get(i);
- drawLookup[cell.getRow()][cell.getColumn()] = true;
- }
-
- // figure out in progress portion of ghosting line
-
- final boolean needToUpdateInProgressPoint = numCircles > 0
- && numCircles < count;
-
- if (needToUpdateInProgressPoint) {
- final float percentageOfNextCircle = ((float) (spotInCycle % MILLIS_PER_CIRCLE_ANIMATING))
- / MILLIS_PER_CIRCLE_ANIMATING;
-
- final Cell currentCell = pattern.get(numCircles - 1);
- final float centerX = getCenterXForColumn(currentCell.column);
- final float centerY = getCenterYForRow(currentCell.row);
-
- final Cell nextCell = pattern.get(numCircles);
- final float dx = percentageOfNextCircle
- * (getCenterXForColumn(nextCell.column) - centerX);
- final float dy = percentageOfNextCircle
- * (getCenterYForRow(nextCell.row) - centerY);
- mInProgressX = centerX + dx;
- mInProgressY = centerY + dy;
- }
- // TODO: Infinite loop here...
- invalidate();
- }
-
- final Path currentPath = mCurrentPath;
- currentPath.rewind();
-
- // draw the circles
- for (int i = 0; i < 3; i++) {
- float centerY = getCenterYForRow(i);
- for (int j = 0; j < 3; j++) {
- CellState cellState = mCellStates[i][j];
- float centerX = getCenterXForColumn(j);
- float size = cellState.size * cellState.scale;
- float translationY = cellState.translateY;
- drawCircle(canvas, (int) centerX, (int) centerY + translationY,
- size, drawLookup[i][j], cellState.alpha);
- }
- }
-
- // TODO: the path should be created and cached every time we hit-detect
- // a cell
- // only the last segment of the path should be computed here
- // draw the path of the pattern (unless we are in stealth mode)
- final boolean drawPath = !mInStealthMode;
-
- if (drawPath) {
- mPathPaint.setColor(getCurrentColor(true /* partOfPattern */));
-
- boolean anyCircles = false;
- float lastX = 0f;
- float lastY = 0f;
- for (int i = 0; i < count; i++) {
- Cell cell = pattern.get(i);
-
- // only draw the part of the pattern stored in
- // the lookup table (this is only different in the case
- // of animation).
- if (!drawLookup[cell.row][cell.column]) {
- break;
- }
- anyCircles = true;
-
- float centerX = getCenterXForColumn(cell.column);
- float centerY = getCenterYForRow(cell.row);
- if (i != 0) {
- CellState state = mCellStates[cell.row][cell.column];
- currentPath.rewind();
- currentPath.moveTo(lastX, lastY);
- if (state.lineEndX != Float.MIN_VALUE
- && state.lineEndY != Float.MIN_VALUE) {
- currentPath.lineTo(state.lineEndX, state.lineEndY);
- } else {
- currentPath.lineTo(centerX, centerY);
- }
- canvas.drawPath(currentPath, mPathPaint);
- }
- lastX = centerX;
- lastY = centerY;
- }
-
- // draw last in progress section
- if ((mPatternInProgress || mPatternDisplayMode == DisplayMode.Animate)
- && anyCircles) {
- currentPath.rewind();
- currentPath.moveTo(lastX, lastY);
- currentPath.lineTo(mInProgressX, mInProgressY);
-
- mPathPaint.setAlpha((int) (calculateLastSegmentAlpha(
- mInProgressX, mInProgressY, lastX, lastY) * 255f));
- canvas.drawPath(currentPath, mPathPaint);
- }
- }
- }
-
- private float calculateLastSegmentAlpha(float x, float y, float lastX,
- float lastY) {
- float diffX = x - lastX;
- float diffY = y - lastY;
- float dist = (float) Math.sqrt(diffX * diffX + diffY * diffY);
- float frac = dist / mSquareWidth;
- return Math.min(1f, Math.max(0f, (frac - 0.3f) * 4f));
- }
-
- private int getCurrentColor(boolean partOfPattern) {
- if (!partOfPattern || mInStealthMode || mPatternInProgress) {
- // unselected circle
- return mRegularColor;
- } else if (mPatternDisplayMode == DisplayMode.Wrong) {
- // the pattern is wrong
- return mErrorColor;
- } else if (mPatternDisplayMode == DisplayMode.Correct
- || mPatternDisplayMode == DisplayMode.Animate) {
- return mSuccessColor;
- } else {
- throw new IllegalStateException("unknown display mode "
- + mPatternDisplayMode);
- }
- }
-
- /**
- * @param partOfPattern
- * Whether this circle is part of the pattern.
- */
- private void drawCircle(Canvas canvas, float centerX, float centerY,
- float size, boolean partOfPattern, float alpha) {
- mPaint.setColor(getCurrentColor(partOfPattern));
- mPaint.setAlpha((int) (alpha * 255));
- canvas.drawCircle(centerX, centerY, size / 2, mPaint);
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
- return new SavedState(superState,
- LockPatternUtils.patternToString(mPattern),
- mPatternDisplayMode.ordinal(), mInputEnabled, mInStealthMode,
- mEnableHapticFeedback);
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- final SavedState ss = (SavedState) state;
- super.onRestoreInstanceState(ss.getSuperState());
- setPattern(DisplayMode.Correct,
- LockPatternUtils.stringToPattern(ss.getSerializedPattern()));
- mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()];
- mInputEnabled = ss.isInputEnabled();
- mInStealthMode = ss.isInStealthMode();
- mEnableHapticFeedback = ss.isTactileFeedbackEnabled();
- }
-
- /**
- * The parecelable for saving and restoring a lock pattern view.
- */
- private static class SavedState extends BaseSavedState {
-
- private final String mSerializedPattern;
- private final int mDisplayMode;
- private final boolean mInputEnabled;
- private final boolean mInStealthMode;
- private final boolean mTactileFeedbackEnabled;
-
- /**
- * Constructor called from {@link LockPatternViewEx#onSaveInstanceState()}
- */
- private SavedState(Parcelable superState, String serializedPattern,
- int displayMode, boolean inputEnabled, boolean inStealthMode,
- boolean tactileFeedbackEnabled) {
- super(superState);
- mSerializedPattern = serializedPattern;
- mDisplayMode = displayMode;
- mInputEnabled = inputEnabled;
- mInStealthMode = inStealthMode;
- mTactileFeedbackEnabled = tactileFeedbackEnabled;
- }
-
- /**
- * Constructor called from {@link #CREATOR}
- */
- private SavedState(Parcel in) {
- super(in);
- mSerializedPattern = in.readString();
- mDisplayMode = in.readInt();
- mInputEnabled = (Boolean) in.readValue(null);
- mInStealthMode = (Boolean) in.readValue(null);
- mTactileFeedbackEnabled = (Boolean) in.readValue(null);
- }
-
- public String getSerializedPattern() {
- return mSerializedPattern;
- }
-
- public int getDisplayMode() {
- return mDisplayMode;
- }
-
- public boolean isInputEnabled() {
- return mInputEnabled;
- }
-
- public boolean isInStealthMode() {
- return mInStealthMode;
- }
-
- public boolean isTactileFeedbackEnabled() {
- return mTactileFeedbackEnabled;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeString(mSerializedPattern);
- dest.writeInt(mDisplayMode);
- dest.writeValue(mInputEnabled);
- dest.writeValue(mInStealthMode);
- dest.writeValue(mTactileFeedbackEnabled);
- }
-
- public static final Parcelable.Creator CREATOR = new Creator() {
-
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-}
diff --git a/LockPatternViewTest/src/com/google/android/collect/Lists.java b/LockPatternViewTest/src/com/google/android/collect/Lists.java
deleted file mode 100644
index b7ffe34..0000000
--- a/LockPatternViewTest/src/com/google/android/collect/Lists.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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.android.collect;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-/**
- * Provides static methods for creating {@code List} instances easily, and other
- * utility methods for working with lists.
- */
-public class Lists {
-
- /**
- * Creates an empty {@code ArrayList} instance.
- *
- *
- * Note: if you only need an immutable empty List, use
- * {@link Collections#emptyList} instead.
- *
- * @return a newly-created, initially-empty {@code ArrayList}
- */
- public static ArrayList newArrayList() {
- return new ArrayList();
- }
-
- /**
- * Creates a resizable {@code ArrayList} instance containing the given
- * elements.
- *
- *
- * Note: due to a bug in javac 1.5.0_06, we cannot support the
- * following:
- *
- *
- * {@code List list = Lists.newArrayList(sub1, sub2);}
- *
- *
- * where {@code sub1} and {@code sub2} are references to subtypes of
- * {@code Base}, not of {@code Base} itself. To get around this, you must
- * use:
- *
- *
- * {@code List list = Lists.newArrayList(sub1, sub2);}
- *
- * @param elements
- * the elements that the list should contain, in order
- * @return a newly-created {@code ArrayList} containing those elements
- */
- public static ArrayList newArrayList(E... elements) {
- int capacity = (elements.length * 110) / 100 + 5;
- ArrayList list = new ArrayList(capacity);
- Collections.addAll(list, elements);
- return list;
- }
-
-}
diff --git a/MigrationNotes.md b/MigrationNotes.md
new file mode 100644
index 0000000..ff867c3
--- /dev/null
+++ b/MigrationNotes.md
@@ -0,0 +1,147 @@
+# …to v3.2 #
+
+Please update your code (Java, XML…) due to these changes:
+
+ * We drop support for APIs < 7.
+ * Rename `EXTRA_INTENT_ACTIVITY_FORGOT_PATTERN` to `EXTRA_PENDING_INTENT_FORGOT_PATTERN`. Note that its value type is also changed from `Intent` to `PendingIntent`.
+
+# …to v3.1 #
+
+Please update your code (Java, XML…) due to these changes:
+
+ * Change package name to `com.haibison.android.lockpattern`.
+ * Change prefixes for resources from:
+ * `alp_` to `alp_42447968_`
+ * `Alp.` to `Alp.42447968.`
+
+You might want to go through the [Quick Use](QuickUse.md) again :-)
+
+# …to v3.0.7 #
+
+There's nothing changed.
+
+# …to v3.0.6 #
+
+There's nothing changed. However we add new support for configuring settings directly via your app's [AndroidManifest.xml](AndroidManifest.md).
+
+# …to v3.0.5 #
+
+Class `Settings.Display`: rename methods `setMaxRetry()` to `setMaxRetries()`, `getMaxRetry()` to `getMaxRetries()`.
+
+# …to v3.0.4 #
+
+Refactor package `prefs` to a single class `util.Settings`:
+
+ * `prefs.Prefs` -> `util.Settings`
+ * `prefs.DisplayPrefs` -> `util.Settings.Display`
+ * `prefs.SecurityPrefs` -> `util.Settings.Security`
+
+# …to v3.0.3 #
+
+There's nothing changed :-)
+
+# …to v3.0 #
+
+Add one more method to interface `IEncrypter`:
+```
+ /**
+ * Decrypts an encrypted pattern.
+ *
+ * @param context
+ * the context.
+ * @param encryptedPattern
+ * the encrypted pattern.
+ * @return the original pattern.
+ */
+ List decrypt(Context context, char[] encryptedPattern);
+```
+
+Please update your code for above change. Basically, it decrypts the encrypted pattern from `encrypt(Context, List)`.
+
+# …to v2.9 #
+
+There's nothing changed :-)
+
+# …to v2.8 #
+
+ * Change method `IEncrypter.encrypt()` from:
+```
+char[] encrypt(Context context, char[] pattern);
+```
+> to:
+```
+char[] encrypt(Context context, List pattern);
+```
+> To keep your last encrypter safe, use helper class `LockPatternUtils`:
+```
+import group.pals.android.lib.ui.lockpattern.widget.LockPatternUtils;
+
+...
+
+ @Override
+ public char[] encrypt(Context context, List pattern) {
+ /*
+ * This is the value that last version passed to your encrypter.
+ */
+ char[] patternAsChars = LockPatternUtils.patternToSha1(pattern)
+ .toCharArray();
+
+ return ...
+ }// encrypt()
+```
+ * Rename `EXTRA_OK_PENDING_INTENT`, `EXTRA_CANCELLED_PENDING_INTENT` to `EXTRA_PENDING_INTENT_OK` and `EXTRA_PENDING_INTENT_CANCELLED`.
+ * Add new extra `EXTRA_INTENT_ACTIVITY_FORGOT_PATTERN` to help the user recover the pattern if he/ she forgot it. Check [QuickUse](QuickUse#%22Forgot_pattern%3F%22.md) for details. This leads to some changes below:
+ * `ACTION_COMPARE_PATTERN`: there are _**4 possible result codes**_: `RESULT_OK`, `RESULT_CANCELED`, `LockPatternActivity.RESULT_FAILED` and `LockPatternActivity.RESULT_FORGOT_PATTERN`.
+ * `ACTION_VERIFY_CAPTCHA`: there are _**3 possible result codes**_ like above _excluding_ `RESULT_FORGOT_PATTERN`.
+
+# …to v2.7 #
+
+There's nothing changed. We've added new action named `ACTION_VERIFY_CAPTCHA`. You simply use it with new `Intent` and the library will do the rest. To change default wired dots (which is `4`), use helper class `DisplayPrefs`:
+```
+import group.pals.android.lib.ui.lockpattern.prefs.DisplayPrefs;
+
+...
+
+DisplayPrefs.setCaptchaWiredDots(your-context, 9);
+```
+
+# …to v2.6 #
+
+ * Change coding style: use `UPPER_CASE` for all `static final` fields and enums.
+ * Move all dynamic settings to `SharedPreferences`. For example all these keys were deleted: ~~`_EncrypterClass`~~, ~~`_StealthMode`~~… Check QuickUse again for details.
+ * Change interface `IEncrypter`. Please see [Encryption](https://code.google.com/p/android-lockpattern/wiki/Encryption) for further details.
+ * Please note that the pattern is now hold in key `EXTRA_PATTERN` and it is a `char[]` array (_not_ `String`).
+
+# …to v2.5 #
+
+## Important notes ##
+
+ * We've added four built-in themes. In order to let the library work properly, you have to use one of them. Because the themes contain resources that the library needs. They are: `Alp_Theme_Dark`, `Alp_Theme_Light`, `Alp_Theme_Dialog_Dark` and `Alp_Theme_Dialog_Light`.
+ * In mode comparing pattern, **_if_** the user fails to pass the process, the library will return result code `LockPatternActivity._ResultFailed` (**_not_** `RESULT_CANCELED`). **_Please note_** that there are _**[3 possible result codes](QuickUse#Let_the_user_identify_himself_with_lock_pattern.md)**_. You might want to take a look at the [demo project](https://code.google.com/p/android-lockpattern/source/browse/demo) for further information.
+
+# …to v2.4 #
+
+Key ~~`_Mode`~~ and enum ~~`LPMode`~~ were removed. Now you configure handlers via action names:
+ * Use `_ActionCreatePattern` to create new pattern
+ * Use `_ActionComparePattern` to compare pattern
+(Check [Usage](QuickUse#Usage.md)).
+
+# …to v2.3 #
+
+To reduce binary size, we removed all keys/ methods which were deprecated and were notified and kept in at least one older version (for migrating purpose):
+ * Key `LockPatternActivity.`~~`_PaternSha1`~~
+ * Method `IEncrypter.`~~`encrypt(String)`~~
+
+# …to v2.1 #
+
+ * [Encryption](https://code.google.com/p/android-lockpattern/wiki/Encryption): Method `IEncrypter.`~~`encrypt(String)`~~ is _deprecated_ and _no longer used_. Please use this new method instead:
+```
+String IEncrypter.encrypt(Context, String);
+```
+
+# …to v2 #
+
+From version 2, key `LockPatternActivity`.~~`_PaternSha1`~~ is _deprecated_ and _no longer used_. Please use this new key instead:
+```
+LockPatternActivity._Pattern
+```
\ No newline at end of file
diff --git a/NOTICE b/NOTICE
deleted file mode 100644
index 08f2bcb..0000000
--- a/NOTICE
+++ /dev/null
@@ -1,17 +0,0 @@
-android-lockpattern
-Copyright 2012 Hai Bison
-
-This product includes software developed at
-https://code.google.com/p/android-lockpattern/
-
-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/ProjectHome.md b/ProjectHome.md
new file mode 100644
index 0000000..4109611
--- /dev/null
+++ b/ProjectHome.md
@@ -0,0 +1,28 @@
+<wiki:gadget url="https://android-lockpattern.googlecode.com/hg/resources/gadgets/main\_header.xml" height="70" width="50%" border="1" />
+
+Android has one useful tool in security settings, it is Lock Pattern. Users can define their own lock pattern ‒ which is a combination of 4+ dots.
+
+We have extracted this piece of code from Android source code, [platform/frameworks/base](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/com/android/internal/widget/). Then modified it a little, to make it easy to use in an application.
+
+ * **Latest stable: v3.2 (#45)** (January 19th, 2015). _From version `3.1.1 beta (#44)`, this project follows [Semantic Versioning](https://en.wikipedia.org/wiki/Semantic_versioning#Semantic_versioning)._
+ * The demo can be downloaded on [Google Play](https://play.google.com/store/apps/details?id=group.pals.android.lib.ui.lockpattern.demo). It needs some more permissions to help us monetize it. With this service we are able to create more great apps and libraries for you guys. _Thank you for your understanding._
+ * Latest source is available in the demo app. You can export it directly to SD card or to Google Drive, Dropbox...
+
+### Features ###
+
+ * Requires: Android 2.1+ (API 7+).
+ * Supports: Eclipse IDE, Android Studio (beta).
+ * _No dependencies._
+ * Designed for both _phones and tablets_.
+ * Stealth mode (invisible pattern).
+ * 5 built-in themes:
+ * Dark/Light
+ * Light with dark action bar (available from API 7+, but only works from API 14+)
+ * Dark/Light dialogs
+ * Ability to generate and let the user verify CAPTCHA pattern.
+
+### Notes ###
+
+ * If you're upgrading the library, refer to [Migration Notes](MigrationNotes.md) first.
+ * For more information about usage, see Wiki pages. Or you might want to see [Quick Use](QuickUse.md).
+ * You're welcome to file new issues on [Issues](https://code.google.com/p/android-lockpattern/issues/list) section.
\ No newline at end of file
diff --git a/QuickUse.md b/QuickUse.md
new file mode 100644
index 0000000..4bd345c
--- /dev/null
+++ b/QuickUse.md
@@ -0,0 +1,273 @@
+# Integrating (Eclipse IDE) #
+
+**First,** you have to open this project in Eclipse. Assuming you place this library at `/data/projects/android-lockpattern`.
+
+**If** you use Ant: to re-generate your `local.properties`, open terminal, use `android` tool (in SDK):
+```
+# [Android SDK]/tools/android update project -p /data/projects/android-lockpattern/code --target android-19
+```
+
+**Then, import** this library into your project:
+
+ * By Eclipse: Right click on your project, select _Properties_, select _Android_ tab, then add this library to _Library_ box.
+ * Manual: Open your _project.properties_ file, add this line:
+```
+android.library.reference.1=/data/projects/android-lockpattern/code
+```
+> _Note:_ `1` is the sequence number of the library. Reset it to fit your project. Perhaps it starts from `1`, I don't know :-D
+
+**Import** [LockPatternActivity](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html) into your application:
+ * By Eclipse: Open `AndroidManifest.xml` -> tab _Application_ -> box _Application Nodes_, click _Add_, select `Activity`. Go to box _Attributes for Activity_, click _Browse_ (next to field _Name_), then add `LockPatternActivity`.
+ * Manual: Open `AndroidManifest.xml`, inside tag `application`, add this:
+```
+
+```
+
+**Note** that there are 5 built-in themes:
+
+ * `Alp.42447968.Theme.Dark`
+ * `Alp.42447968.Theme.Light`
+ * `Alp.42447968.Theme.Light.DarkActionBar` (available from API 7+, but only works from API 14+)
+ * `Alp.42447968.Theme.Dialog.Dark`
+ * `Alp.42447968.Theme.Dialog.Light`
+
+You _have to_ use one of them in order to let the library work properly. Because the themes contain resources that the library needs.
+
+**Android** team recommends that you should set your target SDK to the newest one. You can still use the library for Android 1.6+. For example:
+```
+
+
+
+ ...
+```
+
+ * To avoid the activity from being killed after screen orientation changed, add this:
+```
+
+```
+
+# Usage #
+
+## Create new pattern ##
+
+```
+...
+// This is your preferred flag
+private static final int REQ_CREATE_PATTERN = 1;
+
+...
+
+Intent intent = new Intent(LockPatternActivity.ACTION_CREATE_PATTERN, null,
+ your-context, LockPatternActivity.class);
+startActivityForResult(intent, REQ_CREATE_PATTERN);
+```
+
+For more secure, you might want to use [Encryption](Encryption.md).
+
+## And to get the result ##
+
+```
+@Override
+protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ switch (requestCode) {
+ case REQ_CREATE_PATTERN: {
+ if (resultCode == RESULT_OK) {
+ char[] pattern = data.getCharArrayExtra(
+ LockPatternActivity.EXTRA_PATTERN);
+ ...
+ }
+ break;
+ }// REQ_CREATE_PATTERN
+ }
+}
+```
+
+## Let the user identify himself with lock pattern ##
+
+```
+...
+// This is your preferred flag
+private static final int REQ_ENTER_PATTERN = 2;
+
+...
+
+char[] savedPattern = ...
+
+Intent intent = new Intent(LockPatternActivity.ACTION_COMPARE_PATTERN, null,
+ your-context, LockPatternActivity.class);
+intent.putExtra(LockPatternActivity.EXTRA_PATTERN, savedPattern);
+startActivityForResult(intent, REQ_ENTER_PATTERN);
+```
+```
+...
+@Override
+protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ switch (requestCode) {
+ case REQ_ENTER_PATTERN: {
+ /*
+ * NOTE that there are 4 possible result codes!!!
+ */
+ switch (resultCode) {
+ case RESULT_OK:
+ // The user passed
+ break;
+ case RESULT_CANCELED:
+ // The user cancelled the task
+ break;
+ case LockPatternActivity.RESULT_FAILED:
+ // The user failed to enter the pattern
+ break;
+ case LockPatternActivity.RESULT_FORGOT_PATTERN:
+ // The user forgot the pattern and invoked your recovery Activity.
+ break;
+ }
+
+ /*
+ * In any case, there's always a key EXTRA_RETRY_COUNT, which holds
+ * the number of tries that the user did.
+ */
+ int retryCount = data.getIntExtra(
+ LockPatternActivity.EXTRA_RETRY_COUNT, 0);
+
+ break;
+ }// REQ_ENTER_PATTERN
+ }
+}
+```
+
+## Notes ##
+
+ * You can tell the library to store newly created pattern into [SharedPreferences](http://developer.android.com/reference/android/content/SharedPreferences.html). So you might not need to specify pattern for action [ACTION\_COMPARE\_PATTERN](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html#ACTION_COMPARE_PATTERN). By default, this flag is off. To turn it on:
+```
+import com.haibison.android.lockpattern.util.Settings;
+
+...
+
+Settings.Security.setAutoSavePattern(your-context, true);
+```
+ * [ACTION\_COMPARE\_PATTERN](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html#ACTION_COMPARE_PATTERN): there are _**4 possible result codes**_ like the sample above.
+ * [ACTION\_VERIFY\_CAPTCHA](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html#ACTION_VERIFY_CAPTCHA): there are _**3 possible result codes**_ like the sample above _excluding_ [RESULT\_FORGOT\_PATTERN](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html#RESULT_FORGOT_PATTERN).
+
+# Tips #
+
+## Themes ##
+
+ * To turn `LockPatternActivity` into a dialog, open _**your**_ `AndroidManifest.xml` and add this:
+```
+
+```
+
+ * To change theme in runtime, you must set theme in `AndroidManifest.xml` as above. If you don't do that and set theme to dialog via code, the background of `LockPatternActivity` will be _not_ transparent. A correct example:
+```
+...
+intent.putExtra(LockPatternActivity.EXTRA_THEME, R.style.Alp_42447968_Theme_Dialog_Dark);
+```
+
+## Stealth Mode ##
+
+In stealth mode, there will be no visible feedback as the user enters the pattern. To turn it on, use helper class [Settings.Display](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/util/Settings.Display.html). By default this mode if off.
+```
+import com.haibison.android.lockpattern.util.Settings;
+
+...
+
+Settings.Display.setStealthMode(your-context, true);
+```
+
+## CAPTCHA ##
+
+To let the library generate a random [CAPTCHA](http://en.wikipedia.org/wiki/CAPTCHA) pattern and have the user verify it, you can use action [ACTION\_VERIFY\_CAPTCHA](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html#ACTION_VERIFY_CAPTCHA). Default wired dots is `4`, you can change it with helper class `Settings.Display`.
+```
+...
+Settings.Display.setCaptchaWiredDots(your-context, 9);
+Intent intent = new Intent(LockPatternActivity.ACTION_VERIFY_CAPTCHA, null,
+ your-context, LockPatternActivity.class);
+startActivityForResult(intent, your-request-code);
+```
+
+## Forgot pattern? ##
+
+If you use [ACTION\_COMPARE\_PATTERN](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html#ACTION_COMPARE_PATTERN), the user might forget his/ her pattern. So, you can use a `PendingIntent` of your `Activity` to help the user recover the pattern when he/she needs. For example:
+
+```
+PendingIntent piForgotPattern = ...
+
+Intent intentActivity = new Intent(
+ LockPatternActivity.ACTION_COMPARE_PATTERN, null,
+ your-context, LockPatternActivity.class);
+intentActivity.putExtra(
+ LockPatternActivity.EXTRA_PENDING_INTENT_FORGOT_PATTERN,
+ piForgotPattern);
+...
+```
+
+When the user taps the button _"Forgot pattern?"_ (on `LockPatternActivity`), the library _makes a call_ to start your pending intent, then finishes itself with [RESULT\_FORGOT\_PATTERN](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/LockPatternActivity.html#RESULT_FORGOT_PATTERN).
+
+## Action Bar Icons ##
+
+Version 3+ includes an icon set for action bar, which has dark and light icons.
+
+|  |  |
+|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+
+If you use one of built-in themes (`R.style.Alp_42447968_Theme_*`) for your activity, you can make a reference to the icon like:
+
+```
+
+
+```
+
+Or if you use your own themes, use the icons directly instead of that reference. For example:
+
+```
+
+
+
+
+
+
+
+
+```
+
+If you want more, the SVG source file is available [here](https://code.google.com/p/android-lockpattern/source/browse/resources/images/controls/alp_42447968_ic_action_lockpattern.svg).
+
+# Other Notes #
+
+## Default language ##
+
+Default language is English. It is located at `res/values/strings.xml`. Actually it is a copy of `res/values-en/strings.xml`. So you can change it to your preferred language.
+
+If you'd like to contribute your translation, we thank you :-)
+
+## `AndroidManifest.xml` ##
+
+All configurations with helper class [Settings](http://docs.android-lockpattern.googlecode.com/hg/com/haibison/android/lockpattern/util/Settings.html) (and all of its nested classes) must be called before you start `LockPatternActivity`. But you _can_ configure settings in an activity and call `LockPatternActivity` in another activity.
+
+You can also configure settings directly via your app's [AndroidManifest.xml](AndroidManifest.md).
\ No newline at end of file
diff --git a/README.md b/README.md
deleted file mode 100644
index 8f39799..0000000
--- a/README.md
+++ /dev/null
@@ -1,265 +0,0 @@
-# android-lockpattern
-
-* Version: 3.2.1 beta (#46)
-
-Feel free to contact us at:
-
-* E-mails:
- + haibison.apps[at]gmail.com
-
-In short, you can use this library in your closed source/commercial apps with
-or without our knowledge. Hope you enjoy it :-)
-
-
-# CREDITS
-
-We sincerely thank all of our friends -- who have been contributing to this
-project. We hope this project will be always useful for everyone.
-
-* C
-* [Steven Byle](http://stackoverflow.com/users/1507439/steven-byle)
-* Thomas Breitbach
-* Yan Cheng Cheok (Project Admin of [JStock](http://jstock.sourceforge.net/))
-* And others.
-
-
-# HISTORY
-
-* Version 3.2.1 beta (#46)
- + *Initialize: January 23rd, 2015*
-
-* Version 3.2 (#45)
- + *Release:* January 19th, 2015
- + Update based code from AOSP Lollipop.
- + Drop support for APIs < 7.
- + Add static helper methods for creating new `Intent`'s and calling
- `startActivityForResult(Intent, int)` from an `Activity`, framework
- `Fragment` or support library `Fragment`.
- + Rename `EXTRA_INTENT_ACTIVITY_FORGOT_PATTERN` to
- `EXTRA_PENDING_INTENT_FORGOT_PATTERN`. Note that its value type is also
- changed from `Intent` to `PendingIntent`.
- + Fix small issues.
-
-* Version 3.1.1 beta (#44)
- + *Initialize:* April 04, 2014
-
-* Version 3.1 (#43)
- + *Release:* March 10, 2014
- + Change package name to `com.haibison.android.lockpattern`.
- + Change prefixes:
- - From `alp_` to `alp_42447968_`.
- - From `Alp.` to `Alp.42447968.`.
- + Optimize code and make some other minor changes.
-
-* Version 3.0.8 beta
- + *Initialize:* February 26, 2014
-
-* Version 3.0.7
- + *Release:* February 21, 2014
- + Fix `NullPointerException` while loading settings from manifest.
-
-* Version 3.0.6
- + *Release:* February 19, 2014
- + Add support to directly configure settings via AndroidManifest.xml (tag
- ``).
-
-* Version 3.0.6 beta
- + *Initialize:* February 18, 2014
-
-* Version 3.0.5
- + *Release:* Feburary 12, 2014
- + Add `SimpleWeakEncryption`.
- + Update `LockPatternView` to branch `kitkat-release` (commit:
- `c46c4a6765196bcabf3ea89771a1f9067b22baad`).
- + Update Javadocs, some minor changes...
-
-* Version 3.0.5 beta
- + *Initialize:* January 12, 2014
-
-* Version 3.0.4
- + *Release:* January 12, 2014
- + Refactor package `prefs` to a single class `util.Settings`.
- + Add `LoadingDialog` for the case that implementation of `IEncrypter` takes
- lots of time to finish.
-
-* Version 3.0.4 beta
- + *Initialize:* January 11, 2014
-
-* Version 3.0.3
- + *Release:* December 18, 2013
- + Optimize code.
-
-* Version 3.0.2
- + *Release:* December 18, 2013
- + Add theme light with dark action bar (for API 14+).
-
-* Version 3.0.1
- + *Release:* October 10, 2013
- + Use default icon set (from AOSP).
-
-* Version 3.0
- + *Release:* September 15, 2013
- + Upgrade IEncrypter.
-
-* Version 2.9
- + *Release:* August 11, 2013
- + Fix dialog themes in API 11.
- + Optimize code.
-
-* Version 2.9 beta
- + *Initialize:* July 05, 2013
-
-* Version 2.8
- + *Release:* July 02, 2013
- + Add new extra `EXTRA_INTENT_ACTIVITY_FORGOT_PATTERN` to help the user
- recover the pattern if he/ she forgot it.
- + Change `char[] IEncrypter.encrypt(Context, char[])` to
- `char[] IEncrypter.encrypt(Context, List)`.
- + Rename `EXTRA_OK_PENDING_INTENT`, `EXTRA_CANCELLED_PENDING_INTENT` to
- `EXTRA_PENDING_INTENT_OK` and `EXTRA_PENDING_INTENT_CANCELLED`.
- + Optimize code.
- + Some minor changes...
-
-* Version 2.8 beta
- + *Initialize:* June 20, 2013
-
-* Version 2.7
- + *Release:* June 20, 2013
- + Add new action `ACTION_VERIFY_CAPTCHA`.
-
-* Version 2.7 beta
- + *Initialize:* May 28, 2013
-
-* Version 2.6
- + *Release:* May 18, 2013
- + Use `UPPER_CASE` for `static final` fields and enums;
- + Move most of dynamic settings to `SharedPreferences`;
- + Change `IEncrypter`;
-
-* Version 2.6 beta
- + *Initialize:* May 15, 2013
-
-* Version 2.5.1
- + *Release:* April 15, 2013
- + Fix delivering result to `ResultReceiver`.
-
-* Version 2.5
- + *Release:* April 15, 2013
- + Upgrade UI;
- + Add options:
- - for setting minimum wired dots in mode creating pattern;
- - for setting maximum tries and determining the number of tries that the
- user did in mode comparing patterns;
- - thanks to David Myers for his feedbacks;
- + Use fixed size for `LockPatternActivity` in large screens with dialog
- themes;
- + Add options for sending result to a `PendingIntent` and/ or
- `ResultReceiver`;
- + Fix minor bugs; optimize code;
-
-* Version 2.5 beta
- + *Initialize:* March 18, 2013
-
-* Version 2.4
- + *Release:* March 16, 2013
- + Merge latest code from AOSP;
- + Use action names instead of extra fields for different types of handlers:
- - `_ActionCreatePattern`
- - `_ActionComparePattern`
- + Add built-in themes: default dark and dark dialog;
- + Add stealth-mode;
- + New icon set;
- + Optimize code and UI; special thanks to
- [Steven Byle](http://stackoverflow.com/users/1507439/steven-byle):
- -
-
-* Version 2.3
- + Update info: August 28, 2012
- + The
- [serious bug](https://code.google.com/p/android-lockpattern/issues/detail?id=1)
- was invalid.
-
-* Version 2.3
- + *Release:* August 28, 2012
- + Fixed serious bug: key `_PaternSha1` is deprecated but is used to return
- the pattern;
- + Removed all fields/ methods which were deprecated in old versions;
-
-* Version 2.2
- + *Release:* August 17, 2012
- + added: Spanish language; special thanks to C. - a kind friend who helped
- us translate the library into his mother language;
-
-* Version 2.1
- + *Release:* July 29, 2012
- + turn off `AutoSave` by default;
- + add new method `IEncrypter.encrypt(Context, String);`
- + set method `IEncrypter.encrypt(String)` as deprecated;
-
-* Version 2.1 beta
- + Initialization: July 21, 2012
-
-* Version 2
- + *Release:* July 15, 2012
- + add support for encryption;
-
-* Version 2 beta
- + Initialization: July 12, 2012
-
-* Version 1.5.5
- + *Release:* June 22, 2012
- + set max width and height for `LockPatternView` to `400dp` for tablet;
-
-* Version 1.5.4
- + *Release:* June 09, 2012
- + Fix bug: in mode `CreatePattern`, `LockPatternActivity` recognized wrong
- the confirmed pattern;
-
-* Version 1.5.4 beta
- + Initialization: June 07, 2012
-
-* Version 1.5.3
- + *Release:* June 07, 2012
- + ability to change theme in runtime;
- + save and restore controls' state after screen orientation changed;
-
-* Version 1.5.3 beta
- + Initialization: May 21, 2012
- + make `LockPatternView`'s gravity center;
-
-* Version 1.5.2
- + *Release:* May 21, 2012
- + in landscape mode, move button `Cancel` to bottom;
-
-* Version 1.5.1
- + *Release:* May 21, 2012
- + set `LockPatternView`'s gravity center;
-
-* Version 1.5
- + *Release:* May 21, 2012
- + due to
- [this bug](https://code.google.com/p/android/issues/detail?id=30622), so
- we prefix all resource names with `alp_`;
- + add layout for landscape mode;
- + update coding style:
- - prefix global fields with `m`;
- - prefix static final fields with `_`;
-
-* Version 1.4
- + *Release:* April 29, 2012
- + change UI;
- + determine and use user's haptic feedback;
-
-* Version 1.2
- + *Release:* March 09, 2012
- + make sure `LockPatternUtils.patternToSha1()` returns lower case string;
-
-* Version 1.1
- + *Release:* March 08, 2012
- + fix security issue about using `SharedPreferences`;
-
-* Version 1.0
- + *Release:* March 08, 2012
- + first release;
- + create pattern;
- + compare to existing pattern;
diff --git a/code/.classpath b/code/.classpath
deleted file mode 100644
index 7bc01d9..0000000
--- a/code/.classpath
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/code/.project b/code/.project
deleted file mode 100644
index 0c95dde..0000000
--- a/code/.project
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
- android-lockpattern
-
-
-
-
-
- com.android.ide.eclipse.adt.ResourceManagerBuilder
-
-
-
-
- com.android.ide.eclipse.adt.PreCompilerBuilder
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- com.android.ide.eclipse.adt.ApkBuilder
-
-
-
-
-
- com.android.ide.eclipse.adt.AndroidNature
- org.eclipse.jdt.core.javanature
-
-
diff --git a/code/AndroidManifest.xml b/code/AndroidManifest.xml
deleted file mode 100644
index 9a83049..0000000
--- a/code/AndroidManifest.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/code/build.xml b/code/build.xml
deleted file mode 100644
index 5327a8d..0000000
--- a/code/build.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/code/proguard.cfg b/code/proguard.cfg
deleted file mode 100644
index b1cdf17..0000000
--- a/code/proguard.cfg
+++ /dev/null
@@ -1,40 +0,0 @@
--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 ;
-}
-
--keepclasseswithmembers class * {
- public (android.content.Context, android.util.AttributeSet);
-}
-
--keepclasseswithmembers class * {
- public (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/code/project.properties b/code/project.properties
deleted file mode 100644
index 62bd840..0000000
--- a/code/project.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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-21
-android.library=true
-proguard.config=proguard.cfg
diff --git a/code/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png b/code/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png
deleted file mode 100644
index 911f3fe..0000000
Binary files a/code/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png and /dev/null differ
diff --git a/code/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_light.9.png b/code/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_light.9.png
deleted file mode 100644
index 2129567..0000000
Binary files a/code/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_light.9.png and /dev/null differ
diff --git a/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_dark.png b/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_dark.png
deleted file mode 100644
index 9bddca6..0000000
Binary files a/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_dark.png and /dev/null differ
diff --git a/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png b/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png
deleted file mode 100644
index e160999..0000000
Binary files a/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png and /dev/null differ
diff --git a/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_light.png b/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_light.png
deleted file mode 100644
index 7f4f109..0000000
Binary files a/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_light.png and /dev/null differ
diff --git a/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_light_disabled.png b/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_light_disabled.png
deleted file mode 100644
index aec42be..0000000
Binary files a/code/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_light_disabled.png and /dev/null differ
diff --git a/code/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png b/code/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png
deleted file mode 100644
index dc37316..0000000
Binary files a/code/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png and /dev/null differ
diff --git a/code/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_light.9.png b/code/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_light.9.png
deleted file mode 100644
index 0c5770a..0000000
Binary files a/code/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_light.9.png and /dev/null differ
diff --git a/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_dark.png b/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_dark.png
deleted file mode 100644
index c25c114..0000000
Binary files a/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_dark.png and /dev/null differ
diff --git a/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png b/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png
deleted file mode 100644
index 756c8a0..0000000
Binary files a/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png and /dev/null differ
diff --git a/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_light.png b/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_light.png
deleted file mode 100644
index 87421bd..0000000
Binary files a/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_light.png and /dev/null differ
diff --git a/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_light_disabled.png b/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_light_disabled.png
deleted file mode 100644
index 471994a..0000000
Binary files a/code/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_light_disabled.png and /dev/null differ
diff --git a/code/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png b/code/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png
deleted file mode 100644
index 75d36be..0000000
Binary files a/code/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png and /dev/null differ
diff --git a/code/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png b/code/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png
deleted file mode 100644
index d9bd337..0000000
Binary files a/code/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png and /dev/null differ
diff --git a/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_dark.png b/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_dark.png
deleted file mode 100644
index 7fc60b6..0000000
Binary files a/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_dark.png and /dev/null differ
diff --git a/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png b/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png
deleted file mode 100644
index 29b927b..0000000
Binary files a/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png and /dev/null differ
diff --git a/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_light.png b/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_light.png
deleted file mode 100644
index 772c7d5..0000000
Binary files a/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_light.png and /dev/null differ
diff --git a/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_light_disabled.png b/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_light_disabled.png
deleted file mode 100644
index 710d699..0000000
Binary files a/code/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_light_disabled.png and /dev/null differ
diff --git a/code/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png b/code/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png
deleted file mode 100644
index b029809..0000000
Binary files a/code/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png and /dev/null differ
diff --git a/code/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png b/code/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png
deleted file mode 100644
index 63dd192..0000000
Binary files a/code/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png and /dev/null differ
diff --git a/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_dark.png b/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_dark.png
deleted file mode 100644
index 2fa1222..0000000
Binary files a/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_dark.png and /dev/null differ
diff --git a/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png b/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png
deleted file mode 100644
index 777aa72..0000000
Binary files a/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png and /dev/null differ
diff --git a/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_light.png b/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_light.png
deleted file mode 100644
index 27e01ea..0000000
Binary files a/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_light.png and /dev/null differ
diff --git a/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_light_disabled.png b/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_light_disabled.png
deleted file mode 100644
index 7602045..0000000
Binary files a/code/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_light_disabled.png and /dev/null differ
diff --git a/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_dark.png b/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_dark.png
deleted file mode 100644
index 0bd4615..0000000
Binary files a/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_dark.png and /dev/null differ
diff --git a/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png b/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png
deleted file mode 100644
index 0688d45..0000000
Binary files a/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_dark_disabled.png and /dev/null differ
diff --git a/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_light.png b/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_light.png
deleted file mode 100644
index 3269aec..0000000
Binary files a/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_light.png and /dev/null differ
diff --git a/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_light_disabled.png b/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_light_disabled.png
deleted file mode 100644
index 6d5cacc..0000000
Binary files a/code/res/drawable-xxxhdpi/alp_42447968_ic_action_lockpattern_light_disabled.png and /dev/null differ
diff --git a/code/res/drawable/alp_42447968_selector_ic_action_lockpattern_dark.xml b/code/res/drawable/alp_42447968_selector_ic_action_lockpattern_dark.xml
deleted file mode 100644
index cbc14dc..0000000
--- a/code/res/drawable/alp_42447968_selector_ic_action_lockpattern_dark.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/code/res/drawable/alp_42447968_selector_ic_action_lockpattern_light.xml b/code/res/drawable/alp_42447968_selector_ic_action_lockpattern_light.xml
deleted file mode 100644
index 288316f..0000000
--- a/code/res/drawable/alp_42447968_selector_ic_action_lockpattern_light.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/code/res/layout/alp_42447968_lock_pattern_activity.xml b/code/res/layout/alp_42447968_lock_pattern_activity.xml
deleted file mode 100644
index 8ea63bb..0000000
--- a/code/res/layout/alp_42447968_lock_pattern_activity.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/code/res/layout/alp_42447968_lock_pattern_activity_land.xml b/code/res/layout/alp_42447968_lock_pattern_activity_land.xml
deleted file mode 100644
index 0ad8a3f..0000000
--- a/code/res/layout/alp_42447968_lock_pattern_activity_land.xml
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/code/res/layout/alp_42447968_view_group_progress_bar.xml b/code/res/layout/alp_42447968_view_group_progress_bar.xml
deleted file mode 100644
index e4788bf..0000000
--- a/code/res/layout/alp_42447968_view_group_progress_bar.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/code/res/values-de/strings.xml b/code/res/values-de/strings.xml
deleted file mode 100644
index c85782f..0000000
--- a/code/res/values-de/strings.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
-
-
-
-
- Bestätigen
- Weiter
- Muster vergessen?
- Wiederholen
- Wird geladen…
- Zelle hinzugefügt
- Muster gelöscht
- Muster abgeschlossen
- Entsperrungsmuster gestartet
- Verbinde mind. 4 Punkte.\nVersuche es bitte erneut…
- Zeichne Entsperrungsmuster:
- Zum Entsperren Muster zeichnen:
- Muster aufgezeichnet!
- Muster wiederholen:
- Loslassen wenn fertig
- Entschuldigung, bitte erneut versuchen.
- Dein neues Entsperrungsmuster:
-
-
- Verbinde mind. %1$d Punkt.\nVersuche es bitte erneut…
- Verbinde mind. %1$d Punkte.\nVersuche es bitte erneut…
-
-
-
\ No newline at end of file
diff --git a/code/res/values-en/strings.xml b/code/res/values-en/strings.xml
deleted file mode 100644
index 6017fbc..0000000
--- a/code/res/values-en/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
- Confirm
- Continue
- Forgot pattern?
- Retry
- Loading…
- Cell added
- Pattern cleared
- Pattern completed
- Pattern started
- Connect at least 4 dots.\nTry again…
- Draw an unlock pattern:
- Draw pattern to unlock:
- Pattern recorded!
- Redraw pattern to confirm:
- Release finger when done
- Sorry, try again
- Your new unlock pattern:
-
-
- Connect at least %1$d dot.\nTry again…
- Connect at least %1$d dots.\nTry again…
-
-
-
\ No newline at end of file
diff --git a/code/res/values-es/strings.xml b/code/res/values-es/strings.xml
deleted file mode 100644
index 4bacf50..0000000
--- a/code/res/values-es/strings.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
-
-
-
-
- Confirmar
- Continuar
- ¿Has olvidado el patrón?
- Reintentar
- Cargando…
- Celda añadida
- Patrón limpiado
- Patrón completado
- Patrón empezado
- Conecta al menos 4 puntos.\nIntentalo de nuevo…
- Dibuja un patrón de desbloqueo:
- Dibuja el patrón de desbloqueo:
- Patrón guardado!
- Dibujar de nuevo para confirmar:
- Levanta el dedo cuando termines
- Lo siento, intentalo de nuevo
- Nuevo patrón de desbloqueo:
-
-
- Conecta al menos %1$d punto.\nIntentalo de nuevo…
- Conecta al menos %1$d puntos.\nIntentalo de nuevo…
-
-
-
\ No newline at end of file
diff --git a/code/res/values-land/layouts.xml b/code/res/values-land/layouts.xml
deleted file mode 100644
index 05906a0..0000000
--- a/code/res/values-land/layouts.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- @layout/alp_42447968_lock_pattern_activity_land
-
-
\ No newline at end of file
diff --git a/code/res/values-v11/styles.xml b/code/res/values-v11/styles.xml
deleted file mode 100644
index 0f59083..0000000
--- a/code/res/values-v11/styles.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/code/res/values-v14/styles.xml b/code/res/values-v14/styles.xml
deleted file mode 100644
index b7e5c41..0000000
--- a/code/res/values-v14/styles.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/code/res/values-v21/styles.xml b/code/res/values-v21/styles.xml
deleted file mode 100644
index 117dc6d..0000000
--- a/code/res/values-v21/styles.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/code/res/values-vi/strings.xml b/code/res/values-vi/strings.xml
deleted file mode 100644
index b27b7c5..0000000
--- a/code/res/values-vi/strings.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
-
- Xác nhận
- Tiếp tục
- Quên rồi?
- Thử lại
- Đang tải…
- Đã thêm điểm
- Đã xóa mẫu khóa
- Hoàn thành mẫu khóa
- Bắt đầu mẫu khóa
- Kết nối ít nhứt 4 điểm.\nHãy thử lại…
- Vẽ mẫu khóa:
- Vẽ mẫu khóa để truy cập:
- Mẫu khóa đã được nhớ!
- Vẽ lại mẫu khóa để xác nhận:
- Thả ngón tay khi xong
- Xin lỗi, hãy thử lại
- Mẫu khóa mới của bạn:
-
-
- Kết nối ít nhứt %1$d điểm.\nHãy thử lại…
-
-
-
diff --git a/code/res/values/colors.xml b/code/res/values/colors.xml
deleted file mode 100644
index a93a408..0000000
--- a/code/res/values/colors.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
-
-
-
-
- #ffffffff
- #ffffffff
- #fff4511e
- #ff37474f
- #ff009688
- #fff4511e
- #cc515151
-
-
-
- #ff303030
- #ffeeeeee
-
-
\ No newline at end of file
diff --git a/code/res/values/dimens.xml b/code/res/values/dimens.xml
deleted file mode 100644
index 1a5ea79..0000000
--- a/code/res/values/dimens.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
- 350dp
- 1dp
- 3dp
- 12dp
- 28dp
-
-
\ No newline at end of file
diff --git a/code/res/values/drawables.xml b/code/res/values/drawables.xml
deleted file mode 100644
index 11e58f3..0000000
--- a/code/res/values/drawables.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/code/res/values/preferences.xml b/code/res/values/preferences.xml
deleted file mode 100644
index a8e6743..0000000
--- a/code/res/values/preferences.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
- alp.pkey.sys.pattern
- alp.pkey.sys.auto_save_pattern
- alp.pkey.sys.encrypter_class
- alp.pkey.display.stealth_mode
- alp.pkey.display.min_wired_dots
- alp.pkey.display.max_retries
- alp.pkey.display.captcha_wired_dots
-
- false
- false
-
- 4
- 5
- 4
-
-
\ No newline at end of file
diff --git a/code/res/values/strings.xml b/code/res/values/strings.xml
deleted file mode 120000
index 3611ed1..0000000
--- a/code/res/values/strings.xml
+++ /dev/null
@@ -1 +0,0 @@
-../values-en/strings.xml
\ No newline at end of file
diff --git a/code/res/values/styles.xml b/code/res/values/styles.xml
deleted file mode 100644
index 7632000..0000000
--- a/code/res/values/styles.xml
+++ /dev/null
@@ -1,157 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @null
- @null
-
-
-
-
-
-
\ No newline at end of file
diff --git a/code/src/haibison/android/lockpattern/LockPatternActivity.java b/code/src/haibison/android/lockpattern/LockPatternActivity.java
deleted file mode 100644
index bbd8fe7..0000000
--- a/code/src/haibison/android/lockpattern/LockPatternActivity.java
+++ /dev/null
@@ -1,1206 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern;
-
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-import static haibison.android.lockpattern.BuildConfig.DEBUG;
-import static haibison.android.lockpattern.util.AlpSettings.Display.METADATA_CAPTCHA_WIRED_DOTS;
-import static haibison.android.lockpattern.util.AlpSettings.Display.METADATA_MAX_RETRIES;
-import static haibison.android.lockpattern.util.AlpSettings.Display.METADATA_MIN_WIRED_DOTS;
-import static haibison.android.lockpattern.util.AlpSettings.Display.METADATA_STEALTH_MODE;
-import static haibison.android.lockpattern.util.AlpSettings.Security.METADATA_AUTO_SAVE_PATTERN;
-import static haibison.android.lockpattern.util.AlpSettings.Security.METADATA_ENCRYPTER_CLASS;
-import haibison.android.lockpattern.util.AlpSettings;
-import haibison.android.lockpattern.util.AlpSettings.Display;
-import haibison.android.lockpattern.util.AlpSettings.Security;
-import haibison.android.lockpattern.util.IEncrypter;
-import haibison.android.lockpattern.util.InvalidEncrypterException;
-import haibison.android.lockpattern.util.LoadingView;
-import haibison.android.lockpattern.util.UI;
-import haibison.android.lockpattern.widget.LockPatternUtils;
-import haibison.android.lockpattern.widget.LockPatternView;
-import haibison.android.lockpattern.widget.LockPatternView.Cell;
-import haibison.android.lockpattern.widget.LockPatternView.DisplayMode;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Configuration;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.Button;
-import android.widget.TextView;
-
-/**
- * Main activity for this library.
- *
- * You can deliver result to {@link PendingIntent}'s and/ or
- * {@link ResultReceiver} too. See {@link #EXTRA_PENDING_INTENT_OK},
- * {@link #EXTRA_PENDING_INTENT_CANCELLED} and {@link #EXTRA_RESULT_RECEIVER}
- * for more details.
- *
- *
- *
NOTES
- *
- *
- * You must use one of built-in actions when calling this activity. They start
- * with {@code ACTION_*}. Otherwise the library might behave strangely (we don't
- * cover those cases).
- *
You must use one of the themes that this library supports. They start
- * with {@code R.style.Alp_42447968_Theme_*}. The reason is the themes contain
- * resources that the library needs.
- *
With {@link #ACTION_COMPARE_PATTERN}, there are 4 possible result
- * codes: {@link Activity#RESULT_OK}, {@link Activity#RESULT_CANCELED},
- * {@link #RESULT_FAILED} and {@link #RESULT_FORGOT_PATTERN}.
- *
With {@link #ACTION_VERIFY_CAPTCHA}, there are 3 possible result
- * codes: {@link Activity#RESULT_OK}, {@link Activity#RESULT_CANCELED},
- * and {@link #RESULT_FAILED}.
- *
- *
- * @author Hai Bison
- * @since v1.0
- */
-public class LockPatternActivity extends Activity {
-
- private static final String CLASSNAME = LockPatternActivity.class.getName();
-
- /**
- * Use this action to create new pattern. You can provide an
- * {@link IEncrypter} with
- * {@link Security#setEncrypterClass(android.content.Context, Class)} to
- * improve security.
- *
- * If the user created a pattern, {@link Activity#RESULT_OK} returns with
- * the pattern ({@link #EXTRA_PATTERN}). Otherwise
- * {@link Activity#RESULT_CANCELED} returns.
- *
- * @see #EXTRA_PENDING_INTENT_OK
- * @see #EXTRA_PENDING_INTENT_CANCELLED
- * @since v2.4 beta
- */
- public static final String ACTION_CREATE_PATTERN = CLASSNAME
- + ".create_pattern";
-
- /**
- * Creates new intent with {@link #ACTION_CREATE_PATTERN}. You must call
- * this intent from a UI thread.
- *
- * @param context
- * the context.
- * @return new intent.
- */
- public static Intent newIntentToCreatePattern(Context context) {
- Intent result = new Intent(ACTION_CREATE_PATTERN, null, context,
- LockPatternActivity.class);
- return result;
- }// newIntentToCreatePattern()
-
- /**
- * This method is a shortcut to call
- * {@link #newIntentToCreatePattern(Context)} from a UI thread.
- *
- * @param caller
- * must be an instance of {@link Activity}, or {@link Fragment}
- * or support library's {@code Fragment}. Other values will be
- * ignored.
- * @param context
- * the context.
- * @param requestCode
- * request code for
- * {@link Activity#startActivityForResult(Intent, int)} or
- * counterpart methods of fragments.
- * @return {@code true} if the call has been made successfully,
- * {@code false} if any exception occurred.
- * @throws NullPointerException
- * if caller or context is {@code null}.
- */
- public static boolean startToCreatePattern(Object caller, Context context,
- int requestCode) {
- return callStartActivityForResult(caller,
- newIntentToCreatePattern(context), requestCode);
- }// startToCreatePattern()
-
- /**
- * Calls {@code startActivityForResult(Intent, int)} from given caller,
- * ignores any exception.
- *
- * @param caller
- * the caller.
- * @param intent
- * the intent.
- * @param requestCode
- * request code.
- * @throws NullPointerException
- * if caller or intent is {@code null}.
- * @return {@code true} if the call has been made successfully,
- * {@code false} if any exception occurred.
- */
- public static boolean callStartActivityForResult(Object caller,
- Intent intent, int requestCode) {
- try {
- Method method = caller.getClass().getMethod(
- "startActivityForResult", Intent.class, int.class);
- method.setAccessible(true);
- method.invoke(caller, intent, requestCode);
-
- return true;
- } catch (Exception e) {
- /*
- * Just log it. We don't need to go to details here, as it's
- * responsibility of user to take care of caller.
- */
- if (DEBUG)
- Log.d(CLASSNAME, e.getMessage(), e);
- }
-
- return false;
- }// callStartActivityForResult()
-
- /**
- * Use this action to compare pattern. You provide the pattern to be
- * compared with {@link #EXTRA_PATTERN}.
- *
- * If you enabled feature auto-save pattern before (with
- * {@link Security#setAutoSavePattern(android.content.Context, boolean)} ),
- * then you don't need {@link #EXTRA_PATTERN} at this time. But if you use
- * this extra, its priority is higher than the one stored in shared
- * preferences.
- *
- * You can use {@link #EXTRA_PENDING_INTENT_FORGOT_PATTERN} to help your
- * users in case they forgot the patterns.
- *
- * If the user passes, {@link Activity#RESULT_OK} returns. If not,
- * {@link #RESULT_FAILED} returns.
- *
- * If the user cancels the task, {@link Activity#RESULT_CANCELED} returns.
- *
- * In any case, there will have extra {@link #EXTRA_RETRY_COUNT} available
- * in the intent result.
- *
- * @see #EXTRA_PATTERN
- * @see #EXTRA_PENDING_INTENT_OK
- * @see #EXTRA_PENDING_INTENT_CANCELLED
- * @see #RESULT_FAILED
- * @see #EXTRA_RETRY_COUNT
- * @since v2.4 beta
- */
- public static final String ACTION_COMPARE_PATTERN = CLASSNAME
- + ".compare_pattern";
-
- /**
- * Creates new intent with {@link #ACTION_COMPARE_PATTERN}. You must call
- * this intent from a UI thread.
- *
- * @param context
- * the context.
- * @param pattern
- * optional, see {@link #EXTRA_PATTERN}.
- * @return new intent.
- */
- public static Intent newIntentToComparePattern(Context context,
- char[] pattern) {
- Intent result = new Intent(ACTION_COMPARE_PATTERN, null, context,
- LockPatternActivity.class);
- if (pattern != null)
- result.putExtra(EXTRA_PATTERN, pattern);
-
- return result;
- }// newIntentToComparePattern()
-
- /**
- * This method is a shortcut to call
- * {@link #newIntentToComparePattern(Context, char[])} from a UI thread.
- *
- * @param caller
- * must be an instance of {@link Activity}, or {@link Fragment}
- * or support library's {@code Fragment}. Other values will be
- * ignored.
- * @param context
- * the context.
- * @param requestCode
- * request code for
- * {@link Activity#startActivityForResult(Intent, int)} or
- * counterpart methods of fragments.
- * @param pattern
- * optional, see {@link #EXTRA_PATTERN}.
- * @return {@code true} if the call has been made successfully,
- * {@code false} if any exception occurred.
- * @throws NullPointerException
- * if caller or context is {@code null}.
- */
- public static boolean startToComparePattern(Object caller, Context context,
- int requestCode, char[] pattern) {
- return callStartActivityForResult(caller,
- newIntentToComparePattern(context, pattern), requestCode);
- }// startToComparePattern()
-
- /**
- * Use this action to let the activity generate a random pattern and ask the
- * user to re-draw it to verify.
- *
- * The default length of the auto-generated pattern is {@code 4}. You can
- * change it with
- * {@link Display#setCaptchaWiredDots(android.content.Context, int)}.
- *
- * @since v2.7 beta
- */
- public static final String ACTION_VERIFY_CAPTCHA = CLASSNAME
- + ".verify_captcha";
-
- /**
- * Creates new intent with {@link #ACTION_VERIFY_CAPTCHA}. You must call
- * this intent from a UI thread.
- *
- * @param context
- * the context.
- * @return new intent.
- */
- public static Intent newIntentToVerifyCaptcha(Context context) {
- Intent result = new Intent(ACTION_VERIFY_CAPTCHA, null, context,
- LockPatternActivity.class);
- return result;
- }// newIntentToVerifyCaptcha()
-
- /**
- * This method is a shortcut to call
- * {@link #newIntentToVerifyCaptcha(Context)} from a UI thread.
- *
- * @param caller
- * must be an instance of {@link Activity}, or {@link Fragment}
- * or support library's {@code Fragment}. Other values will be
- * ignored.
- * @param context
- * the context.
- * @param requestCode
- * request code for
- * {@link Activity#startActivityForResult(Intent, int)} or
- * counterpart methods of fragments.
- * @return {@code true} if the call has been made successfully,
- * {@code false} if any exception occurred.
- * @throws NullPointerException
- * if caller or context is {@code null}.
- */
- public static boolean startToVerifyCaptcha(Object caller, Context context,
- int requestCode) {
- return callStartActivityForResult(caller,
- newIntentToVerifyCaptcha(context), requestCode);
- }// startToVerifyCaptcha()
-
- /**
- * If you use {@link #ACTION_COMPARE_PATTERN} and the user fails to "login"
- * after a number of tries, this activity will finish with this result code.
- *
- * @see #ACTION_COMPARE_PATTERN
- * @see #EXTRA_RETRY_COUNT
- */
- public static final int RESULT_FAILED = RESULT_FIRST_USER + 1;
-
- /**
- * If you use {@link #ACTION_COMPARE_PATTERN} and the user forgot his/ her
- * pattern and decided to ask for your help with recovering the pattern (
- * {@link #EXTRA_PENDING_INTENT_FORGOT_PATTERN}), this activity will finish
- * with this result code.
- *
- * @see #ACTION_COMPARE_PATTERN
- * @see #EXTRA_RETRY_COUNT
- * @see #EXTRA_PENDING_INTENT_FORGOT_PATTERN
- * @since v2.8 beta
- */
- public static final int RESULT_FORGOT_PATTERN = RESULT_FIRST_USER + 2;
-
- /**
- * For actions {@link #ACTION_COMPARE_PATTERN} and
- * {@link #ACTION_VERIFY_CAPTCHA}, this key holds the number of tries that
- * the user attempted to verify the input pattern.
- */
- public static final String EXTRA_RETRY_COUNT = CLASSNAME + ".retry_count";
-
- /**
- * Sets value of this key to a theme in {@code R.style.Alp_42447968_Theme_*}
- * . Default is the one you set in your {@code AndroidManifest.xml}. Note
- * that theme {@link R.style#Alp_42447968_Theme_Light_DarkActionBar} is
- * available in API 4+, but it only works in API 14+.
- *
- * @since v1.5.3 beta
- */
- public static final String EXTRA_THEME = CLASSNAME + ".theme";
-
- /**
- * Key to hold the pattern. It must be a {@code char[]} array.
- *
- *
- *
If you use encrypter, it should be an encrypted array.
- *
If you don't use encrypter, it should be the SHA-1 value of the
- * actual pattern. You can generate the value by
- * {@link LockPatternUtils#patternToSha1(List)}.
- *
- *
- * @since v2 beta
- */
- public static final String EXTRA_PATTERN = CLASSNAME + ".pattern";
-
- /**
- * You can provide an {@link ResultReceiver} with this key. The activity
- * will notify your receiver the same result code and intent data as you
- * will receive them in {@link #onActivityResult(int, int, Intent)}.
- *
- * @since v2.4 beta
- */
- public static final String EXTRA_RESULT_RECEIVER = CLASSNAME
- + ".result_receiver";
-
- /**
- * Put a {@link PendingIntent} into this key. It will be sent before
- * {@link Activity#RESULT_OK} will be returning. If you were calling this
- * activity with {@link #ACTION_CREATE_PATTERN}, key {@link #EXTRA_PATTERN}
- * will be attached to the original intent which the pending intent holds.
- *
- *
Notes
- *
- *
If you're going to use an activity, you don't need
- * {@link Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library
- * will call it inside {@link LockPatternActivity} .
- *
- */
- public static final String EXTRA_PENDING_INTENT_OK = CLASSNAME
- + ".pending_intent_ok";
-
- /**
- * Put a {@link PendingIntent} into this key. It will be sent before
- * {@link Activity#RESULT_CANCELED} will be returning.
- *
- *
Notes
- *
- *
If you're going to use an activity, you don't need
- * {@link Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library
- * will call it inside {@link LockPatternActivity} .
- *
- */
- public static final String EXTRA_PENDING_INTENT_CANCELLED = CLASSNAME
- + ".pending_intent_cancelled";
-
- /**
- * You put a {@link PendingIntent} into this extra. The library will show a
- * button "Forgot pattern?" and call your intent later when the user
- * taps it.
- *
- *
Notes
- *
- *
If you use an activity, you don't need
- * {@link Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library
- * will call it inside {@link LockPatternActivity} .
- *
{@link LockPatternActivity} will finish with
- * {@link #RESULT_FORGOT_PATTERN} after making a call to start
- * your pending intent.
- *
It is your responsibility to make sure the Intent is good. The
- * library doesn't cover any errors when calling your intent.
- *
- *
- * @see #ACTION_COMPARE_PATTERN
- * @since v2.8 beta
- * @author Thanks to Yan Cheng Cheok for his idea.
- */
- public static final String EXTRA_PENDING_INTENT_FORGOT_PATTERN = CLASSNAME
- + ".pending_intent_forgot_pattern";
-
- /**
- * Helper enum for button OK commands. (Because we use only one "OK" button
- * for different commands).
- *
- * @author Hai Bison
- */
- private static enum ButtonOkCommand {
- CONTINUE, FORGOT_PATTERN, DONE
- }// ButtonOkCommand
-
- /**
- * Delay time to reload the lock pattern view after a wrong pattern.
- */
- private static final long DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW = SECOND_IN_MILLIS;
-
- /*
- * FIELDS
- */
- private int mMaxRetries, mMinWiredDots, mRetryCount = 0, mCaptchaWiredDots;
- private boolean mAutoSave, mStealthMode;
- private IEncrypter mEncrypter;
- private ButtonOkCommand mBtnOkCmd;
- private Intent mIntentResult;
- private LoadingView mLoadingView;
-
- /*
- * CONTROLS
- */
- private TextView mTextInfo;
- private LockPatternView mLockPatternView;
- private View mFooter;
- private Button mBtnCancel;
- private Button mBtnConfirm;
- private View mViewGroupProgressBar;
-
- /**
- * Called when the activity is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- if (DEBUG)
- Log.d(CLASSNAME, "ClassName = " + CLASSNAME);
-
- /*
- * EXTRA_THEME
- */
-
- if (getIntent().hasExtra(EXTRA_THEME))
- setTheme(getIntent().getIntExtra(EXTRA_THEME,
- R.style.Alp_42447968_Theme_Dark));
-
- super.onCreate(savedInstanceState);
-
- loadSettings();
-
- mIntentResult = new Intent();
- setResult(RESULT_CANCELED, mIntentResult);
-
- initContentView();
- }// onCreate()
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
-
- if (DEBUG)
- Log.d(CLASSNAME, "onConfigurationChanged()");
-
- initContentView();
- }// onConfigurationChanged()
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- /*
- * Use this hook instead of onBackPressed(), because onBackPressed() is
- * not available in API 4.
- */
- if (keyCode == KeyEvent.KEYCODE_BACK
- && ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- if (mLoadingView != null)
- mLoadingView.cancel(true);
-
- finishWithNegativeResult(RESULT_CANCELED);
-
- return true;
- }// if
-
- return super.onKeyDown(keyCode, event);
- }// onKeyDown()
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- /*
- * Support canceling dialog on touching outside in APIs < 11.
- *
- * This piece of code is copied from android.view.Window. You can find
- * it by searching for methods shouldCloseOnTouch() and isOutOfBounds().
- */
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
- && event.getAction() == MotionEvent.ACTION_DOWN
- && getWindow().peekDecorView() != null) {
- final int x = (int) event.getX();
- final int y = (int) event.getY();
- final int slop = ViewConfiguration.get(this)
- .getScaledWindowTouchSlop();
- final View decorView = getWindow().getDecorView();
- boolean isOutOfBounds = (x < -slop) || (y < -slop)
- || (x > (decorView.getWidth() + slop))
- || (y > (decorView.getHeight() + slop));
- if (isOutOfBounds) {
- finishWithNegativeResult(RESULT_CANCELED);
- return true;
- }
- }// if
-
- return super.onTouchEvent(event);
- }// onTouchEvent()
-
- @Override
- protected void onDestroy() {
- if (mLoadingView != null)
- mLoadingView.cancel(true);
-
- super.onDestroy();
- }// onDestroy()
-
- /**
- * Loads settings, either from manifest or {@link AlpSettings}.
- */
- private void loadSettings() {
- Bundle metaData = null;
- try {
- metaData = getPackageManager().getActivityInfo(getComponentName(),
- PackageManager.GET_META_DATA).metaData;
- } catch (NameNotFoundException e) {
- /*
- * Never catch this.
- */
- e.printStackTrace();
- }
-
- if (metaData != null && metaData.containsKey(METADATA_MIN_WIRED_DOTS))
- mMinWiredDots = AlpSettings.Display.validateMinWiredDots(this,
- metaData.getInt(METADATA_MIN_WIRED_DOTS));
- else
- mMinWiredDots = AlpSettings.Display.getMinWiredDots(this);
-
- if (metaData != null && metaData.containsKey(METADATA_MAX_RETRIES))
- mMaxRetries = AlpSettings.Display.validateMaxRetries(this,
- metaData.getInt(METADATA_MAX_RETRIES));
- else
- mMaxRetries = AlpSettings.Display.getMaxRetries(this);
-
- if (metaData != null
- && metaData.containsKey(METADATA_AUTO_SAVE_PATTERN))
- mAutoSave = metaData.getBoolean(METADATA_AUTO_SAVE_PATTERN);
- else
- mAutoSave = AlpSettings.Security.isAutoSavePattern(this);
-
- if (metaData != null
- && metaData.containsKey(METADATA_CAPTCHA_WIRED_DOTS))
- mCaptchaWiredDots = AlpSettings.Display.validateCaptchaWiredDots(
- this, metaData.getInt(METADATA_CAPTCHA_WIRED_DOTS));
- else
- mCaptchaWiredDots = AlpSettings.Display.getCaptchaWiredDots(this);
-
- if (metaData != null && metaData.containsKey(METADATA_STEALTH_MODE))
- mStealthMode = metaData.getBoolean(METADATA_STEALTH_MODE);
- else
- mStealthMode = AlpSettings.Display.isStealthMode(this);
-
- /*
- * Encrypter.
- */
- char[] encrypterClass;
- if (metaData != null && metaData.containsKey(METADATA_ENCRYPTER_CLASS))
- encrypterClass = metaData.getString(METADATA_ENCRYPTER_CLASS)
- .toCharArray();
- else
- encrypterClass = AlpSettings.Security.getEncrypterClass(this);
-
- if (encrypterClass != null) {
- try {
- mEncrypter = (IEncrypter) Class.forName(
- new String(encrypterClass), false, getClassLoader())
- .newInstance();
- } catch (Throwable t) {
- throw new InvalidEncrypterException();
- }
- }
- }// loadSettings()
-
- /**
- * Initializes UI...
- */
- private void initContentView() {
- /*
- * Save all controls' state to restore later.
- */
- CharSequence infoText = mTextInfo != null ? mTextInfo.getText() : null;
- Boolean btnOkEnabled = mBtnConfirm != null ? mBtnConfirm.isEnabled()
- : null;
- LockPatternView.DisplayMode lastDisplayMode = mLockPatternView != null ? mLockPatternView
- .getDisplayMode() : null;
- List lastPattern = mLockPatternView != null ? mLockPatternView
- .getPattern() : null;
-
- setContentView(R.layout.alp_42447968_lock_pattern_activity);
- UI.adjustDialogSizeForLargeScreens(getWindow());
-
- /*
- * MAP CONTROLS
- */
-
- mTextInfo = (TextView) findViewById(R.id.alp_42447968_textview_info);
- mLockPatternView = (LockPatternView) findViewById(R.id.alp_42447968_view_lock_pattern);
-
- mFooter = findViewById(R.id.alp_42447968_viewgroup_footer);
- mBtnCancel = (Button) findViewById(R.id.alp_42447968_button_cancel);
- mBtnConfirm = (Button) findViewById(R.id.alp_42447968_button_confirm);
-
- mViewGroupProgressBar = findViewById(R.id.alp_42447968_view_group_progress_bar);
-
- /*
- * SETUP CONTROLS
- */
-
- mViewGroupProgressBar
- .setOnClickListener(mViewGroupProgressBarOnClickListener);
-
- /*
- * LOCK PATTERN VIEW
- */
-
- switch (getResources().getConfiguration().screenLayout
- & Configuration.SCREENLAYOUT_SIZE_MASK) {
- case Configuration.SCREENLAYOUT_SIZE_LARGE:
- case Configuration.SCREENLAYOUT_SIZE_XLARGE: {
- final int size = getResources().getDimensionPixelSize(
- R.dimen.alp_42447968_lockpatternview_size);
- LayoutParams lp = mLockPatternView.getLayoutParams();
- lp.width = size;
- lp.height = size;
- mLockPatternView.setLayoutParams(lp);
-
- break;
- }// LARGE / XLARGE
- }
-
- /*
- * Haptic feedback.
- */
- boolean hapticFeedbackEnabled = false;
- try {
- hapticFeedbackEnabled = android.provider.Settings.System
- .getInt(getContentResolver(),
- android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED,
- 0) != 0;
- } catch (Throwable t) {
- /*
- * Ignore it.
- */
- }
- mLockPatternView.setTactileFeedbackEnabled(hapticFeedbackEnabled);
-
- mLockPatternView.setInStealthMode(mStealthMode
- && !ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction()));
- mLockPatternView.setOnPatternListener(mLockPatternViewListener);
- if (lastPattern != null && lastDisplayMode != null
- && !ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction()))
- mLockPatternView.setPattern(lastDisplayMode, lastPattern);
-
- /*
- * COMMAND BUTTONS
- */
-
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
- mBtnCancel.setOnClickListener(mBtnCancelOnClickListener);
- mBtnConfirm.setOnClickListener(mBtnConfirmOnClickListener);
-
- mBtnCancel.setVisibility(View.VISIBLE);
- mFooter.setVisibility(View.VISIBLE);
-
- if (infoText != null)
- mTextInfo.setText(infoText);
- else
- mTextInfo
- .setText(R.string.alp_42447968_msg_draw_an_unlock_pattern);
-
- /*
- * BUTTON OK
- */
- if (mBtnOkCmd == null)
- mBtnOkCmd = ButtonOkCommand.CONTINUE;
- switch (mBtnOkCmd) {
- case CONTINUE:
- mBtnConfirm.setText(R.string.alp_42447968_cmd_continue);
- break;
- case DONE:
- mBtnConfirm.setText(R.string.alp_42447968_cmd_confirm);
- break;
- default:
- /*
- * Do nothing.
- */
- break;
- }
- if (btnOkEnabled != null)
- mBtnConfirm.setEnabled(btnOkEnabled);
- }// ACTION_CREATE_PATTERN
- else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- if (TextUtils.isEmpty(infoText))
- mTextInfo
- .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock);
- else
- mTextInfo.setText(infoText);
- if (getIntent().hasExtra(EXTRA_PENDING_INTENT_FORGOT_PATTERN)) {
- mBtnConfirm.setOnClickListener(mBtnConfirmOnClickListener);
- mBtnConfirm.setText(R.string.alp_42447968_cmd_forgot_pattern);
- mBtnConfirm.setEnabled(true);
- mFooter.setVisibility(View.VISIBLE);
- }
- }// ACTION_COMPARE_PATTERN
- else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
-
- /*
- * NOTE: EXTRA_PATTERN should hold a char[] array. In this case we
- * use it as a temporary variable to hold a list of Cell.
- */
-
- final ArrayList pattern;
- if (getIntent().hasExtra(EXTRA_PATTERN))
- pattern = getIntent()
- .getParcelableArrayListExtra(EXTRA_PATTERN);
- else
- getIntent().putParcelableArrayListExtra(
- EXTRA_PATTERN,
- pattern = LockPatternUtils
- .genCaptchaPattern(mCaptchaWiredDots));
-
- mLockPatternView.setPattern(DisplayMode.Animate, pattern);
- }// ACTION_VERIFY_CAPTCHA
- }// initContentView()
-
- /**
- * Compares {@code pattern} to the given pattern (
- * {@link #ACTION_COMPARE_PATTERN}) or to the generated "CAPTCHA" pattern (
- * {@link #ACTION_VERIFY_CAPTCHA}). Then finishes the activity if they
- * match.
- *
- * @param pattern
- * the pattern to be compared.
- */
- private void doComparePattern(final List pattern) {
- if (pattern == null)
- return;
-
- /*
- * Use a LoadingView because decrypting pattern might take time...
- */
-
- mLoadingView = new LoadingView(this,
- mViewGroupProgressBar) {
-
- @Override
- protected Object doInBackground(Void... params) {
- if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- char[] currentPattern = getIntent().getCharArrayExtra(
- EXTRA_PATTERN);
- if (currentPattern == null)
- currentPattern = AlpSettings.Security
- .getPattern(LockPatternActivity.this);
- if (currentPattern != null) {
- if (mEncrypter != null)
- return pattern.equals(mEncrypter.decrypt(
- LockPatternActivity.this, currentPattern));
- else
- return Arrays.equals(currentPattern,
- LockPatternUtils.patternToSha1(pattern)
- .toCharArray());
- }
- }// ACTION_COMPARE_PATTERN
- else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
- return pattern.equals(getIntent()
- .getParcelableArrayListExtra(EXTRA_PATTERN));
- }// ACTION_VERIFY_CAPTCHA
-
- return false;
- }// doInBackground()
-
- @Override
- protected void onPostExecute(Object result) {
- super.onPostExecute(result);
-
- if ((Boolean) result)
- finishWithResultOk(null);
- else {
- mRetryCount++;
- mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount);
-
- if (mRetryCount >= mMaxRetries)
- finishWithNegativeResult(RESULT_FAILED);
- else {
- mLockPatternView.setDisplayMode(DisplayMode.Wrong);
- mTextInfo.setText(R.string.alp_42447968_msg_try_again);
- mLockPatternView.postDelayed(mLockPatternViewReloader,
- DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
- }
- }
- }// onPostExecute()
-
- };
-
- mLoadingView.execute();
- }// doComparePattern()
-
- /**
- * Checks and creates the pattern.
- *
- * @param pattern
- * the current pattern of lock pattern view.
- */
- private void doCheckAndCreatePattern(final List pattern) {
- if (pattern.size() < mMinWiredDots) {
- mLockPatternView.setDisplayMode(DisplayMode.Wrong);
- mTextInfo.setText(getResources().getQuantityString(
- R.plurals.alp_42447968_pmsg_connect_x_dots, mMinWiredDots,
- mMinWiredDots));
- mLockPatternView.postDelayed(mLockPatternViewReloader,
- DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
- return;
- }// if
-
- if (getIntent().hasExtra(EXTRA_PATTERN)) {
- /*
- * Use a LoadingView because decrypting pattern might take time...
- */
- mLoadingView = new LoadingView(this,
- mViewGroupProgressBar) {
-
- @Override
- protected Object doInBackground(Void... params) {
- if (mEncrypter != null)
- return pattern.equals(mEncrypter.decrypt(
- LockPatternActivity.this, getIntent()
- .getCharArrayExtra(EXTRA_PATTERN)));
- else
- return Arrays.equals(
- getIntent().getCharArrayExtra(EXTRA_PATTERN),
- LockPatternUtils.patternToSha1(pattern)
- .toCharArray());
- }// doInBackground()
-
- @Override
- protected void onPostExecute(Object result) {
- super.onPostExecute(result);
-
- if ((Boolean) result) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_your_new_unlock_pattern);
- mBtnConfirm.setEnabled(true);
- } else {
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
- mBtnConfirm.setEnabled(false);
- mLockPatternView.setDisplayMode(DisplayMode.Wrong);
- mLockPatternView.postDelayed(mLockPatternViewReloader,
- DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
- }
- }// onPostExecute()
-
- };
-
- mLoadingView.execute();
- } else {
- /*
- * Use a LoadingView because encrypting pattern might take time...
- */
- mLoadingView = new LoadingView(this,
- mViewGroupProgressBar) {
-
- @Override
- protected Object doInBackground(Void... params) {
- return mEncrypter != null ? mEncrypter.encrypt(
- LockPatternActivity.this, pattern)
- : LockPatternUtils.patternToSha1(pattern)
- .toCharArray();
- }// onCancel()
-
- @Override
- protected void onPostExecute(Object result) {
- super.onPostExecute(result);
-
- getIntent().putExtra(EXTRA_PATTERN, (char[]) result);
- mTextInfo
- .setText(R.string.alp_42447968_msg_pattern_recorded);
- mBtnConfirm.setEnabled(true);
- }// onPostExecute()
-
- };
-
- mLoadingView.execute();
- }
- }// doCheckAndCreatePattern()
-
- /**
- * Finishes activity with {@link Activity#RESULT_OK}.
- *
- * @param pattern
- * the pattern, if this is in mode creating pattern. In any
- * cases, it can be set to {@code null}.
- */
- private void finishWithResultOk(char[] pattern) {
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction()))
- mIntentResult.putExtra(EXTRA_PATTERN, pattern);
- else {
- /*
- * If the user was "logging in", minimum try count can not be zero.
- */
- mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount + 1);
- }
-
- setResult(RESULT_OK, mIntentResult);
-
- /*
- * ResultReceiver
- */
- ResultReceiver receiver = getIntent().getParcelableExtra(
- EXTRA_RESULT_RECEIVER);
- if (receiver != null) {
- Bundle bundle = new Bundle();
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction()))
- bundle.putCharArray(EXTRA_PATTERN, pattern);
- else {
- /*
- * If the user was "logging in", minimum try count can not be
- * zero.
- */
- bundle.putInt(EXTRA_RETRY_COUNT, mRetryCount + 1);
- }
- receiver.send(RESULT_OK, bundle);
- }
-
- /*
- * PendingIntent
- */
- PendingIntent pi = getIntent().getParcelableExtra(
- EXTRA_PENDING_INTENT_OK);
- if (pi != null) {
- try {
- pi.send(this, RESULT_OK, mIntentResult);
- } catch (Throwable t) {
- Log.e(CLASSNAME, "Error sending PendingIntent: " + pi, t);
- }
- }
-
- finish();
- }// finishWithResultOk()
-
- /**
- * Finishes the activity with negative result (
- * {@link Activity#RESULT_CANCELED}, {@link #RESULT_FAILED} or
- * {@link #RESULT_FORGOT_PATTERN}).
- */
- private void finishWithNegativeResult(int resultCode) {
- if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction()))
- mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount);
-
- setResult(resultCode, mIntentResult);
-
- /*
- * ResultReceiver
- */
- ResultReceiver receiver = getIntent().getParcelableExtra(
- EXTRA_RESULT_RECEIVER);
- if (receiver != null) {
- Bundle resultBundle = null;
- if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- resultBundle = new Bundle();
- resultBundle.putInt(EXTRA_RETRY_COUNT, mRetryCount);
- }
- receiver.send(resultCode, resultBundle);
- }
-
- /*
- * PendingIntent
- */
- PendingIntent pi = getIntent().getParcelableExtra(
- EXTRA_PENDING_INTENT_CANCELLED);
- if (pi != null) {
- try {
- pi.send(this, resultCode, mIntentResult);
- } catch (Throwable t) {
- Log.e(CLASSNAME, "Error sending PendingIntent: " + pi, t);
- }
- }
-
- finish();
- }// finishWithNegativeResult()
-
- /*
- * LISTENERS
- */
-
- /**
- * Pattern listener for LockPatternView.
- */
- private final LockPatternView.OnPatternListener mLockPatternViewListener = new LockPatternView.OnPatternListener() {
-
- @Override
- public void onPatternStart() {
- mLockPatternView.removeCallbacks(mLockPatternViewReloader);
- mLockPatternView.setDisplayMode(DisplayMode.Correct);
-
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_release_finger_when_done);
- mBtnConfirm.setEnabled(false);
- if (mBtnOkCmd == ButtonOkCommand.CONTINUE)
- getIntent().removeExtra(EXTRA_PATTERN);
- }// ACTION_CREATE_PATTERN
- else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock);
- }// ACTION_COMPARE_PATTERN
- else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
- }// ACTION_VERIFY_CAPTCHA
- }// onPatternStart()
-
- @Override
- public void onPatternDetected(List pattern) {
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
- doCheckAndCreatePattern(pattern);
- }// ACTION_CREATE_PATTERN
- else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- doComparePattern(pattern);
- }// ACTION_COMPARE_PATTERN
- else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
- if (!DisplayMode.Animate.equals(mLockPatternView
- .getDisplayMode()))
- doComparePattern(pattern);
- }// ACTION_VERIFY_CAPTCHA
- }// onPatternDetected()
-
- @Override
- public void onPatternCleared() {
- mLockPatternView.removeCallbacks(mLockPatternViewReloader);
-
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
- mLockPatternView.setDisplayMode(DisplayMode.Correct);
- mBtnConfirm.setEnabled(false);
- if (mBtnOkCmd == ButtonOkCommand.CONTINUE) {
- getIntent().removeExtra(EXTRA_PATTERN);
- mTextInfo
- .setText(R.string.alp_42447968_msg_draw_an_unlock_pattern);
- } else
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
- }// ACTION_CREATE_PATTERN
- else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- mLockPatternView.setDisplayMode(DisplayMode.Correct);
- mTextInfo
- .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock);
- }// ACTION_COMPARE_PATTERN
- else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
- List pattern = getIntent().getParcelableArrayListExtra(
- EXTRA_PATTERN);
- mLockPatternView.setPattern(DisplayMode.Animate, pattern);
- }// ACTION_VERIFY_CAPTCHA
- }// onPatternCleared()
-
- @Override
- public void onPatternCellAdded(List pattern) {
- // TODO Auto-generated method stub
- }// onPatternCellAdded()
-
- };// mLockPatternViewListener
-
- /**
- * Click listener for button Cancel.
- */
- private final View.OnClickListener mBtnCancelOnClickListener = new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- finishWithNegativeResult(RESULT_CANCELED);
- }// onClick()
-
- };// mBtnCancelOnClickListener
-
- /**
- * Click listener for button Confirm.
- */
- private final View.OnClickListener mBtnConfirmOnClickListener = new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
- if (mBtnOkCmd == ButtonOkCommand.CONTINUE) {
- mBtnOkCmd = ButtonOkCommand.DONE;
- mLockPatternView.clearPattern();
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
- mBtnConfirm.setText(R.string.alp_42447968_cmd_confirm);
- mBtnConfirm.setEnabled(false);
- } else {
- final char[] pattern = getIntent().getCharArrayExtra(
- EXTRA_PATTERN);
- if (mAutoSave)
- AlpSettings.Security.setPattern(
- LockPatternActivity.this, pattern);
- finishWithResultOk(pattern);
- }
- }// ACTION_CREATE_PATTERN
- else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- /*
- * We don't need to verify the extra. First, this button is only
- * visible if there is this extra in the intent. Second, it is
- * the responsibility of the caller to make sure the extra is
- * good.
- */
- PendingIntent pi = null;
- try {
- pi = getIntent().getParcelableExtra(
- EXTRA_PENDING_INTENT_FORGOT_PATTERN);
- pi.send();
- } catch (Throwable t) {
- Log.e(CLASSNAME, "Error sending pending intent: " + pi, t);
- }
- finishWithNegativeResult(RESULT_FORGOT_PATTERN);
- }// ACTION_COMPARE_PATTERN
- }// onClick()
-
- };// mBtnConfirmOnClickListener
-
- /**
- * This reloads the {@link #mLockPatternView} after a wrong pattern.
- */
- private final Runnable mLockPatternViewReloader = new Runnable() {
-
- @Override
- public void run() {
- mLockPatternView.clearPattern();
- mLockPatternViewListener.onPatternCleared();
- }// run()
-
- };// mLockPatternViewReloader
-
- /**
- * Click listener for view group progress bar.
- */
- private final View.OnClickListener mViewGroupProgressBarOnClickListener = new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- /*
- * Do nothing. We just don't want the user to interact with controls
- * behind this view.
- */
- }// onClick()
-
- };// mViewGroupProgressBarOnClickListener
-
-}
diff --git a/code/src/haibison/android/lockpattern/collect/Lists.java b/code/src/haibison/android/lockpattern/collect/Lists.java
deleted file mode 100644
index bc9d78d..0000000
--- a/code/src/haibison/android/lockpattern/collect/Lists.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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 haibison.android.lockpattern.collect;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-/**
- * Provides static methods for creating {@code List} instances easily, and other
- * utility methods for working with lists.
- */
-public class Lists {
-
- /**
- * Creates an empty {@code ArrayList} instance.
- *
- *
- * Note: if you only need an immutable empty List, use
- * {@link Collections#emptyList} instead.
- *
- * @return a newly-created, initially-empty {@code ArrayList}
- */
- public static ArrayList newArrayList() {
- return new ArrayList();
- }
-
- /**
- * Creates a resizable {@code ArrayList} instance containing the given
- * elements.
- *
- *
- * Note: due to a bug in javac 1.5.0_06, we cannot support the
- * following:
- *
- *
- * {@code List list = Lists.newArrayList(sub1, sub2);}
- *
- *
- * where {@code sub1} and {@code sub2} are references to subtypes of
- * {@code Base}, not of {@code Base} itself. To get around this, you must
- * use:
- *
- *
- * {@code List list = Lists.newArrayList(sub1, sub2);}
- *
- * @param elements
- * the elements that the list should contain, in order
- * @return a newly-created {@code ArrayList} containing those elements
- */
- public static ArrayList newArrayList(E... elements) {
- int capacity = (elements.length * 110) / 100 + 5;
- ArrayList list = new ArrayList(capacity);
- Collections.addAll(list, elements);
- return list;
- }
-
-}
diff --git a/code/src/haibison/android/lockpattern/util/Alp.java b/code/src/haibison/android/lockpattern/util/Alp.java
deleted file mode 100644
index 21bfc86..0000000
--- a/code/src/haibison/android/lockpattern/util/Alp.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern.util;
-
-/**
- * System utilities.
- *
- * @author Hai Bison
- *
- */
-public class Alp {
-
- /**
- * This is singleton class.
- */
- private Alp() {
- }// Alp
-
- /**
- * The library name.
- */
- public static final String LIB_NAME = "android-lockpattern";
-
- /**
- * The library version code.
- */
- public static final int LIB_VERSION_CODE = 46;
-
- /**
- * The library version name.
- */
- public static final String LIB_VERSION_NAME = "3.2.1 beta";
-
- /**
- * The library package name.
- */
- public static final String LIB_PACKAGE_NAME = "com.haibison.android.lockpattern";
-
- /**
- * This unique ID is used for some stuffs such as preferences' file name.
- *
- * @since v2.6 beta
- */
- public static final String UID = "a6eedbe5-1cf9-4684-8134-ad4ec9f6a131";
-
-}
diff --git a/code/src/haibison/android/lockpattern/util/AlpSettings.java b/code/src/haibison/android/lockpattern/util/AlpSettings.java
deleted file mode 100644
index 737fbd6..0000000
--- a/code/src/haibison/android/lockpattern/util/AlpSettings.java
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern.util;
-
-import haibison.android.lockpattern.R;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.Build;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceManager;
-
-/**
- * All settings for the library. They are stored in {@link SharedPreferences}.
- *
- * For some options, you can set them directly via tag {@code }
- * inside tag {@code } in AndroidManifest.xml. Refer to setter methods
- * for details. Note that the values in the manifest get higher priority than
- * the ones from this class.
- *
- * @author Hai Bison
- *
- */
-public class AlpSettings {
-
- /**
- * This is singleton class.
- */
- private AlpSettings() {
- }// AlpSettings
-
- /**
- * Generates global preference filename of this library.
- *
- * @return the global preference filename.
- */
- public static final String genPreferenceFilename() {
- return String.format("%s_%s", Alp.LIB_NAME, Alp.UID);
- }// genPreferenceFilename()
-
- /**
- * Generates global database filename. the database filename.
- *
- * @return the global database filename.
- */
- public static final String genDatabaseFilename(String name) {
- return String.format("%s_%s_%s", Alp.LIB_NAME, Alp.UID, name);
- }// genDatabaseFilename()
-
- /**
- * Gets new {@link SharedPreferences}
- *
- * @param context
- * the context.
- * @return {@link SharedPreferences}
- */
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- public static SharedPreferences p(Context context) {
- /*
- * Always use application context.
- */
- return context.getApplicationContext().getSharedPreferences(
- genPreferenceFilename(), Context.MODE_MULTI_PROCESS);
- }// p()
-
- /**
- * Setup {@code pm} to use global unique filename and global access mode.
- * You must use this method if you let the user change preferences via UI
- * (such as {@link PreferenceActivity}, {@link PreferenceFragment}...).
- *
- * @param context
- * the context.
- * @param pm
- * {@link PreferenceManager}.
- * @since v2.6 beta
- */
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- public static void setupPreferenceManager(Context context,
- PreferenceManager pm) {
- pm.setSharedPreferencesMode(Context.MODE_MULTI_PROCESS);
- pm.setSharedPreferencesName(genPreferenceFilename());
- }// setupPreferenceManager()
-
- /**
- * Display preferences.
- *
- * @author Hai Bison
- *
- */
- public static class Display {
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setStealthMode(Context, boolean)
- */
- public static final String METADATA_STEALTH_MODE = "stealthMode";
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setMinWiredDots(Context, int)
- */
- public static final String METADATA_MIN_WIRED_DOTS = "minWiredDots";
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setMaxRetries(Context, int)
- */
- public static final String METADATA_MAX_RETRIES = "maxRetries";
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setCaptchaWiredDots(Context, int)
- */
- public static final String METADATA_CAPTCHA_WIRED_DOTS = "captchaWiredDots";
-
- /**
- * This is singleton class.
- */
- private Display() {
- }// Display
-
- /**
- * Checks if the library is using stealth mode or not.
- *
- * @param context
- * the context.
- * @return {@code true} or {@code false}. Default is {@code false}.
- */
- public static boolean isStealthMode(Context context) {
- return p(context)
- .getBoolean(
- context.getString(R.string.alp_42447968_pkey_display_stealth_mode),
- context.getResources()
- .getBoolean(
- R.bool.alp_42447968_pkey_display_stealth_mode_default));
- }// isStealthMode()
-
- /**
- * Sets stealth mode.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_STEALTH_MODE}.
- *
- * @param context
- * the context.
- * @param v
- * the value.
- */
- public static void setStealthMode(Context context, boolean v) {
- p(context)
- .edit()
- .putBoolean(
- context.getString(R.string.alp_42447968_pkey_display_stealth_mode),
- v).commit();
- }// setStealthMode()
-
- /**
- * Gets minimum wired dots allowed for a pattern.
- *
- * @param context
- * the context.
- * @return the minimum wired dots allowed for a pattern. Default is
- * {@code 4}.
- */
- public static int getMinWiredDots(Context context) {
- return p(context)
- .getInt(context
- .getString(R.string.alp_42447968_pkey_display_min_wired_dots),
- context.getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_min_wired_dots_default));
- }// getMinWiredDots()
-
- /**
- * Validates min wired dots.
- *
- * @param context
- * the context.
- * @param v
- * the input value.
- * @return the correct value.
- */
- public static int validateMinWiredDots(Context context, int v) {
- if (v <= 0 || v > 9)
- v = context
- .getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_min_wired_dots_default);
- return v;
- }// validateMinWiredDots()
-
- /**
- * Sets minimum wired dots allowed for a pattern.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_MIN_WIRED_DOTS}.
- *
- * @param context
- * the context.
- * @param v
- * the minimum wired dots allowed for a pattern.
- */
- public static void setMinWiredDots(Context context, int v) {
- v = validateMinWiredDots(context, v);
- p(context)
- .edit()
- .putInt(context
- .getString(R.string.alp_42447968_pkey_display_min_wired_dots),
- v).commit();
- }// setMinWiredDots()
-
- /**
- * Gets max retries allowed in mode comparing pattern.
- *
- * @param context
- * the context.
- * @return the max retries allowed in mode comparing pattern. Default is
- * {@code 5}.
- */
- public static int getMaxRetries(Context context) {
- return p(context)
- .getInt(context
- .getString(R.string.alp_42447968_pkey_display_max_retries),
- context.getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_max_retries_default));
- }// getMaxRetries()
-
- /**
- * Validates max retries.
- *
- * @param context
- * the context.
- * @param v
- * the input value.
- * @return the correct value.
- */
- public static int validateMaxRetries(Context context, int v) {
- if (v <= 0)
- v = context
- .getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_max_retries_default);
- return v;
- }// validateMaxRetries()
-
- /**
- * Sets max retries allowed in mode comparing pattern.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_MAX_RETRIES}.
- *
- * @param context
- * the context.
- * @param v
- * the max retries allowed in mode comparing pattern.
- */
- public static void setMaxRetries(Context context, int v) {
- v = validateMaxRetries(context, v);
- p(context)
- .edit()
- .putInt(context
- .getString(R.string.alp_42447968_pkey_display_max_retries),
- v).commit();
- }// setMaxRetries()
-
- /**
- * Gets wired dots for a "CAPTCHA" pattern.
- *
- * @param context
- * the context.
- * @return the wired dots for a "CAPTCHA" pattern. Default is {@code 4}.
- */
- public static int getCaptchaWiredDots(Context context) {
- return p(context)
- .getInt(context
- .getString(R.string.alp_42447968_pkey_display_captcha_wired_dots),
- context.getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_captcha_wired_dots_default));
- }// getCaptchaWiredDots()
-
- /**
- * Validates CAPTCHA wired dots.
- *
- * @param context
- * the context.
- * @param v
- * the input value.
- * @return the correct value.
- */
- public static int validateCaptchaWiredDots(Context context, int v) {
- if (v <= 0 || v > 9)
- v = context
- .getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_captcha_wired_dots_default);
- return v;
- }// validateCaptchaWiredDots()
-
- /**
- * Sets wired dots for a "CAPTCHA" pattern.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_CAPTCHA_WIRED_DOTS}.
- *
- * @param context
- * the context.
- * @param v
- * the wired dots for a "CAPTCHA" pattern.
- */
- public static void setCaptchaWiredDots(Context context, int v) {
- v = validateCaptchaWiredDots(context, v);
- p(context)
- .edit()
- .putInt(context
- .getString(R.string.alp_42447968_pkey_display_captcha_wired_dots),
- v).commit();
- }// setCaptchaWiredDots()
-
- }// Display
-
- /**
- * Security preferences.
- *
- * @author Hai Bison
- *
- */
- public static class Security {
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setEncrypterClass(Context, char[])
- * @see #setEncrypterClass(Context, Class)
- */
- public static final String METADATA_ENCRYPTER_CLASS = "encrypterClass";
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setAutoSavePattern(Context, boolean)
- */
- public static final String METADATA_AUTO_SAVE_PATTERN = "autoSavePattern";
-
- /**
- * This is singleton class.
- */
- private Security() {
- }// Security
-
- /**
- * Checks if the library is using auto-save pattern mode.
- *
- * @param context
- * the context.
- * @return {@code true} or {@code false}. Default is {@code false}.
- */
- public static boolean isAutoSavePattern(Context context) {
- return p(context)
- .getBoolean(
- context.getString(R.string.alp_42447968_pkey_sys_auto_save_pattern),
- context.getResources()
- .getBoolean(
- R.bool.alp_42447968_pkey_sys_auto_save_pattern_default));
- }// isAutoSavePattern()
-
- /**
- * Sets auto-save pattern mode.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_AUTO_SAVE_PATTERN}.
- *
- * @param context
- * the context.
- * @param v
- * the auto-save mode.
- */
- public static void setAutoSavePattern(Context context, boolean v) {
- p(context)
- .edit()
- .putBoolean(
- context.getString(R.string.alp_42447968_pkey_sys_auto_save_pattern),
- v).commit();
- if (!v)
- setPattern(context, null);
- }// setAutoSavePattern()
-
- /**
- * Gets the pattern.
- *
- * @param context
- * the context.
- * @return the pattern. Default is {@code null}.
- */
- public static char[] getPattern(Context context) {
- String pattern = p(context).getString(
- context.getString(R.string.alp_42447968_pkey_sys_pattern),
- null);
- return pattern == null ? null : pattern.toCharArray();
- }// getPattern()
-
- /**
- * Sets the pattern.
- *
- * @param context
- * the context.
- * @param pattern
- * the pattern, can be {@code null} to reset it.
- */
- public static void setPattern(Context context, char[] pattern) {
- p(context)
- .edit()
- .putString(
- context.getString(R.string.alp_42447968_pkey_sys_pattern),
- pattern != null ? new String(pattern) : null)
- .commit();
- }// setPattern()
-
- /**
- * Gets encrypter class.
- *
- * @param context
- * the context.
- * @return the full name of encrypter class. Default is {@code null}.
- */
- public static char[] getEncrypterClass(Context context) {
- String clazz = p(context)
- .getString(
- context.getString(R.string.alp_42447968_pkey_sys_encrypter_class),
- null);
- return clazz == null ? null : clazz.toCharArray();
- }// getEncrypterClass()
-
- /**
- * Sets encrypter class.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_ENCRYPTER_CLASS}.
- *
- * @param context
- * the context.
- * @param clazz
- * the encrypter class, can be {@code null} if you don't want
- * to use it.
- */
- public static void setEncrypterClass(Context context, Class> clazz) {
- setEncrypterClass(context, clazz != null ? clazz.getName()
- .toCharArray() : null);
- }// setEncrypterClass()
-
- /**
- * Sets encrypter class.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_ENCRYPTER_CLASS}.
- *
- * @param context
- * the context.
- * @param clazz
- * the full name of encrypter class, can be {@code null} if
- * you don't want to use it.
- */
- public static void setEncrypterClass(Context context, char[] clazz) {
- p(context)
- .edit()
- .putString(
- context.getString(R.string.alp_42447968_pkey_sys_encrypter_class),
- clazz != null ? new String(clazz) : null).commit();
- }// setEncrypterClass()
-
- }// Security
-
-}
diff --git a/code/src/haibison/android/lockpattern/util/FloatAnimator.java b/code/src/haibison/android/lockpattern/util/FloatAnimator.java
deleted file mode 100644
index 28549f7..0000000
--- a/code/src/haibison/android/lockpattern/util/FloatAnimator.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern.util;
-
-import haibison.android.lockpattern.collect.Lists;
-
-import java.util.List;
-
-import android.os.Handler;
-
-/**
- * Float animator.
- *
- * @author Hai Bison
- *
- */
-public class FloatAnimator {
-
- /**
- * Event listener.
- *
- * @author Hai Bison
- *
- */
- public static interface EventListener {
-
- /**
- * Will be called when animation starts.
- *
- * @param animator
- * the animator.
- */
- void onAnimationStart(FloatAnimator animator);
-
- /**
- * Will be called when new animated value is calculated.
- *
- * @param animator
- * the animator.
- */
- void onAnimationUpdate(FloatAnimator animator);
-
- /**
- * Will be called when animation cancels.
- *
- * @param animator
- * the animator.
- */
- void onAnimationCancel(FloatAnimator animator);
-
- /**
- * Will be called when animation ends.
- *
- * @param animator
- * the animator.
- */
- void onAnimationEnd(FloatAnimator animator);
-
- }// EventListener
-
- /**
- * Simple event listener.
- *
- * @author Hai Bison
- *
- */
- public static class SimpleEventListener implements EventListener {
-
- @Override
- public void onAnimationStart(FloatAnimator animator) {
- }
-
- @Override
- public void onAnimationUpdate(FloatAnimator animator) {
- }
-
- @Override
- public void onAnimationCancel(FloatAnimator animator) {
- }
-
- @Override
- public void onAnimationEnd(FloatAnimator animator) {
- }
-
- }// SimpleEventListener
-
- /**
- * Animation delay, in milliseconds.
- */
- private static final long ANIMATION_DELAY = 1;
-
- private final float mStartValue, mEndValue;
- private final long mDuration;
- private float mAnimatedValue;
-
- private List mEventListeners;
- private Handler mHandler;
- private long mStartTime;
-
- /**
- * Creates new instance.
- *
- * @param start
- * start value.
- * @param end
- * end value.
- * @param duration
- * duration, in milliseconds. This should not be long, as delay
- * value between animation frame is just 1 millisecond.
- */
- public FloatAnimator(float start, float end, long duration) {
- mStartValue = start;
- mEndValue = end;
- mDuration = duration;
-
- mAnimatedValue = mStartValue;
- }// FloatAnimator()
-
- /**
- * Adds event listener.
- *
- * @param listener
- * the listener.
- */
- public void addEventListener(EventListener listener) {
- if (mEventListeners == null)
- mEventListeners = Lists.newArrayList();
- mEventListeners.add(listener);
- }// addEventListener()
-
- /**
- * Gets animated value.
- *
- * @return animated value.
- */
- public float getAnimatedValue() {
- return mAnimatedValue;
- }// getAnimatedValue()
-
- /**
- * Starts animating.
- */
- public void start() {
- if (mHandler != null)
- return;
-
- notifyAnimationStart();
-
- mStartTime = System.currentTimeMillis();
-
- mHandler = new Handler();
- mHandler.post(new Runnable() {
-
- @Override
- public void run() {
- final Handler handler = mHandler;
- if (handler == null)
- return;
-
- final long elapsedTime = System.currentTimeMillis()
- - mStartTime;
- if (elapsedTime > mDuration) {
- mHandler = null;
- notifyAnimationEnd();
- } else {
- float fraction = mDuration > 0 ? (float) (elapsedTime)
- / mDuration : 1f;
- float delta = mEndValue - mStartValue;
- mAnimatedValue = mStartValue + delta * fraction;
-
- notifyAnimationUpdate();
- handler.postDelayed(this, ANIMATION_DELAY);
- }
- }// run()
-
- });
- }// start()
-
- /**
- * Cancels animating.
- */
- public void cancel() {
- if (mHandler == null)
- return;
-
- mHandler.removeCallbacksAndMessages(null);
- mHandler = null;
-
- notifyAnimationCancel();
- notifyAnimationEnd();
- }// cancel()
-
- /**
- * Notifies all listeners that animation starts.
- */
- protected void notifyAnimationStart() {
- final List listeners = mEventListeners;
- if (listeners != null) {
- for (EventListener listener : listeners)
- listener.onAnimationStart(this);
- }// if
- }// notifyAnimationStart()
-
- /**
- * Notifies all listeners that animation updates.
- */
- protected void notifyAnimationUpdate() {
- final List listeners = mEventListeners;
- if (listeners != null) {
- for (EventListener listener : listeners)
- listener.onAnimationUpdate(this);
- }// if
- }// notifyAnimationUpdate()
-
- /**
- * Notifies all listeners that animation cancels.
- */
- protected void notifyAnimationCancel() {
- final List listeners = mEventListeners;
- if (listeners != null) {
- for (EventListener listener : listeners)
- listener.onAnimationCancel(this);
- }// if
- }// notifyAnimationCancel()
-
- /**
- * Notifies all listeners that animation ends.
- */
- protected void notifyAnimationEnd() {
- final List listeners = mEventListeners;
- if (listeners != null) {
- for (EventListener listener : listeners)
- listener.onAnimationEnd(this);
- }// if
- }// notifyAnimationEnd()
-
-}
diff --git a/code/src/haibison/android/lockpattern/util/IEncrypter.java b/code/src/haibison/android/lockpattern/util/IEncrypter.java
deleted file mode 100644
index 0c68431..0000000
--- a/code/src/haibison/android/lockpattern/util/IEncrypter.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern.util;
-
-import haibison.android.lockpattern.widget.LockPatternView.Cell;
-
-import java.util.List;
-
-import android.content.Context;
-
-/**
- * Interface for encrypter.
- *
- * @author Hai Bison
- * @since v2 beta
- */
-public interface IEncrypter {
-
- /**
- * Encrypts {@code pattern}.
- *
- * @param context
- * the context.
- * @param pattern
- * the pattern in the form of a list of {@link Cell}.
- * @return the encrypted char array of the pattern.
- * @since v2.1 beta
- */
- char[] encrypt(Context context, List pattern);
-
- /**
- * Decrypts an encrypted pattern.
- *
- * @param context
- * the context.
- * @param encryptedPattern
- * the encrypted pattern.
- * @return the original pattern.
- */
- List decrypt(Context context, char[] encryptedPattern);
-
-}
diff --git a/code/src/haibison/android/lockpattern/util/InvalidEncrypterException.java b/code/src/haibison/android/lockpattern/util/InvalidEncrypterException.java
deleted file mode 100644
index 4ed64ad..0000000
--- a/code/src/haibison/android/lockpattern/util/InvalidEncrypterException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern.util;
-
-/**
- * Used to throw exception if given class is not implemented from
- * {@link IEncrypter}.
- *
- * @author Hai Bison
- * @since v2 beta
- */
-public class InvalidEncrypterException extends RuntimeException {
-
- /**
- * Auto-generated by Eclipse.
- */
- private static final long serialVersionUID = -1709666714042537187L;
-
-}
diff --git a/code/src/haibison/android/lockpattern/util/LoadingDialog.java b/code/src/haibison/android/lockpattern/util/LoadingDialog.java
deleted file mode 100644
index 5f4b92c..0000000
--- a/code/src/haibison/android/lockpattern/util/LoadingDialog.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern.util;
-
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-import haibison.android.lockpattern.R;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.util.Log;
-
-/**
- * An implementation of {@link AsyncTask}, used to show {@link ProgressDialog}
- * while doing some background tasks.
- *
- * @author Hai Bison
- */
-public abstract class LoadingDialog extends
- AsyncTask {
-
- private static final String CLASSNAME = LoadingDialog.class.getName();
-
- private final ProgressDialog mDialog;
-
- /**
- * Delay time in milliseconds. Default is half a second.
- */
- private long mDelayTime = SECOND_IN_MILLIS / 2;
-
- /**
- * Flag to use along with {@link #mDelayTime}
- */
- private boolean mFinished = false;
-
- private Throwable mLastException;
-
- /**
- * Creates new instance.
- *
- * @param context
- * the context.
- * @param cancelable
- * whether the user can cancel the dialog by tapping outside of
- * it, or by pressing Back button.
- */
- public LoadingDialog(Context context, boolean cancelable) {
- this(context, cancelable, R.string.alp_42447968_loading);
- }// LoadingDialog()
-
- /**
- * Creates new instance.
- *
- * @param context
- * the context.
- * @param cancelable
- * whether the user can cancel the dialog by tapping outside of
- * it, or by pressing Back button.
- * @param msgId
- * the resource ID of the message to be displayed.
- */
- public LoadingDialog(Context context, boolean cancelable, int msgId) {
- this(context, cancelable, context.getString(msgId));
- }// LoadingDialog()
-
- /**
- * Creates new instance.
- *
- * @param context
- * the context.
- * @param cancelable
- * whether the user can cancel the dialog by tapping outside of
- * it, or by pressing Back button.
- * @param msg
- * the message to display.
- */
- public LoadingDialog(Context context, boolean cancelable, CharSequence msg) {
- mDialog = new ProgressDialog(context);
- mDialog.setCancelable(cancelable);
- mDialog.setMessage(msg);
- mDialog.setIndeterminate(true);
-
- if (cancelable) {
- mDialog.setCanceledOnTouchOutside(true);
- mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-
- @Override
- public void onCancel(DialogInterface dialog) {
- cancel(true);
- }// onCancel()
-
- });
- }
- }// LoadingDialog()
-
- /**
- * If you override this method, you must call {@code super.onPreExecute()}
- * at beginning of the method.
- */
- @Override
- protected void onPreExecute() {
- new Handler().postDelayed(new Runnable() {
-
- @Override
- public void run() {
- if (!mFinished) {
- try {
- /*
- * Sometime the activity has been finished before we
- * show this dialog, it will raise error.
- */
- mDialog.show();
- } catch (Throwable t) {
- // TODO
- Log.e(CLASSNAME, "onPreExecute() - show dialog: " + t);
- }
- }
- }
- }, getDelayTime());
- }// onPreExecute()
-
- /**
- * If you override this method, you must call
- * {@code super.onPostExecute(result)} at beginning of the method.
- */
- @Override
- protected void onPostExecute(Result result) {
- doFinish();
- }// onPostExecute()
-
- /**
- * If you override this method, you must call {@code super.onCancelled()} at
- * beginning of the method.
- */
- @Override
- protected void onCancelled() {
- doFinish();
- super.onCancelled();
- }// onCancelled()
-
- private void doFinish() {
- mFinished = true;
- try {
- /*
- * Sometime the activity has been finished before we dismiss this
- * dialog, it will raise error.
- */
- mDialog.dismiss();
- } catch (Throwable t) {
- // TODO
- Log.e(CLASSNAME, "doFinish() - dismiss dialog: " + t);
- }
- }// doFinish()
-
- /**
- * Gets the delay time before showing the dialog.
- *
- * @return the delay time
- */
- public long getDelayTime() {
- return mDelayTime;
- }// getDelayTime()
-
- /**
- * Sets the delay time before showing the dialog.
- *
- * @param delayTime
- * the delay time to set
- * @return the instance of this object, for chaining multiple calls into a
- * single statement.
- */
- public LoadingDialog setDelayTime(int delayTime) {
- mDelayTime = delayTime >= 0 ? delayTime : 0;
- return this;
- }// setDelayTime()
-
- /**
- * Sets last exception. This method is useful in case an exception raises
- * inside {@link #doInBackground(Void...)}
- *
- * @param t
- * {@link Throwable}
- */
- protected void setLastException(Throwable t) {
- mLastException = t;
- }// setLastException()
-
- /**
- * Gets last exception.
- *
- * @return {@link Throwable}
- */
- protected Throwable getLastException() {
- return mLastException;
- }// getLastException()
-
-}
diff --git a/code/src/haibison/android/lockpattern/util/LoadingView.java b/code/src/haibison/android/lockpattern/util/LoadingView.java
deleted file mode 100644
index ae9ee83..0000000
--- a/code/src/haibison/android/lockpattern/util/LoadingView.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern.util;
-
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-import android.content.Context;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.view.View;
-
-/**
- * An implementation of {@link AsyncTask}, used to show a view while doing some
- * background tasks, then hide it when done.
- *
- * @author Hai Bison
- */
-public abstract class LoadingView extends
- AsyncTask {
-
- @SuppressWarnings("unused")
- private static final String CLASSNAME = LoadingView.class.getName();
-
- private final View mView;
-
- /**
- * Delay time in milliseconds. Default delay is half a second.
- */
- private long mDelayTime = SECOND_IN_MILLIS / 2;
-
- /**
- * Flag to use along with {@link #mDelayTime}
- */
- private boolean mFinished = false;
-
- private Throwable mLastException;
-
- /**
- * Creates new instance.
- *
- * @param context
- * the context.
- * @param view
- * the view to be controlled by this async task.
- */
- public LoadingView(Context context, View view) {
- mView = view;
- }// LoadingView()
-
- /**
- * If you override this method, you must call {@code super.onPreExecute()}
- * at beginning of the method.
- */
- @Override
- protected void onPreExecute() {
- new Handler().postDelayed(new Runnable() {
-
- @Override
- public void run() {
- if (!mFinished)
- mView.setVisibility(View.VISIBLE);
- }// run()
-
- }, getDelayTime());
- }// onPreExecute()
-
- /**
- * If you override this method, you must call
- * {@code super.onPostExecute(result)} at beginning of the method.
- */
- @Override
- protected void onPostExecute(Result result) {
- doFinish();
- }// onPostExecute()
-
- /**
- * If you override this method, you must call {@code super.onCancelled()} at
- * beginning of the method.
- */
- @Override
- protected void onCancelled() {
- doFinish();
- super.onCancelled();
- }// onCancelled()
-
- private void doFinish() {
- mFinished = true;
- mView.setVisibility(View.GONE);
- }// doFinish()
-
- /**
- * Gets the delay time before showing the view.
- *
- * @return the delay time, in milliseconds.
- */
- public long getDelayTime() {
- return mDelayTime;
- }// getDelayTime()
-
- /**
- * Sets the delay time before showing the view.
- *
- * @param delayTime
- * the delay time to set, in milliseconds.
- * @return the instance of this object, for chaining multiple calls into a
- * single statement.
- */
- public LoadingView setDelayTime(int delayTime) {
- mDelayTime = delayTime >= 0 ? delayTime : 0;
- return this;
- }// setDelayTime()
-
- /**
- * Sets last exception. This method is useful in case an exception raises
- * inside {@link #doInBackground(Void...)}
- *
- * @param t
- * {@link Throwable}
- */
- protected void setLastException(Throwable t) {
- mLastException = t;
- }// setLastException()
-
- /**
- * Gets last exception.
- *
- * @return {@link Throwable}
- */
- public Throwable getLastException() {
- return mLastException;
- }// getLastException()
-
-}
diff --git a/code/src/haibison/android/lockpattern/util/Randoms.java b/code/src/haibison/android/lockpattern/util/Randoms.java
deleted file mode 100644
index 8f7b8ef..0000000
--- a/code/src/haibison/android/lockpattern/util/Randoms.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern.util;
-
-import haibison.android.lockpattern.collect.Lists;
-
-import java.util.List;
-import java.util.Random;
-
-/**
- * Random utilities.
- *
- * @author Hai Bison
- *
- */
-public class Randoms {
-
- private static final Random RANDOM = new Random();
-
- /**
- * This is singleton class.
- */
- private Randoms() {
- }// Random()
-
- /**
- * Generates a random integer.
- *
- * @return the random integer.
- */
- public static int randInt() {
- return RANDOM.nextInt((int) (System.nanoTime() % Integer.MAX_VALUE));
- }// randInt()
-
- /**
- * Generates a random integer within {@code [0, n)}.
- *
- * @param n
- * an arbitrary value.
- * @return the random integer.
- */
- public static int randInt(int n) {
- return n > 0 ? randInt() % n : 0;
- }// randInt()
-
- /**
- * Generates a random integer array which has length of {@code end - start},
- * and is filled by all values from {@code start} to {@code end - 1} in
- * randomized orders.
- *
- * @param start
- * the starting value.
- * @param end
- * the ending value.
- * @return the random integer array. If {@code end <= start}, an empty array
- * returns.
- */
- public static int[] randIntArray(int start, int end) {
- if (end <= start)
- return new int[0];
-
- final List values = Lists.newArrayList();
- for (int i = start; i < end; i++)
- values.add(i);
-
- final int[] result = new int[values.size()];
- for (int i = 0; i < result.length; i++) {
- int k = randInt(values.size());
- result[i] = values.get(k);
- values.remove(k);
- }// for
-
- return result;
- }// randIntArray()
-
- /**
- * Generates a random integer array which has length of {@code end}, and is
- * filled by all values from {@code 0} to {@code end - 1} in randomized
- * orders.
- *
- * @param end
- * the ending value.
- * @return the random integer array. If {@code end <= start}, an empty array
- * returns.
- */
- public static int[] randIntArray(int end) {
- return randIntArray(0, end);
- }// randIntArray()
-
-}
diff --git a/code/src/haibison/android/lockpattern/util/ResourceUtils.java b/code/src/haibison/android/lockpattern/util/ResourceUtils.java
deleted file mode 100644
index 982d58d..0000000
--- a/code/src/haibison/android/lockpattern/util/ResourceUtils.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern.util;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.TypedValue;
-
-/**
- * Resources' utilities.
- *
- * @author Hai Bison
- *
- */
-public class ResourceUtils {
-
- /**
- * This is singleton class.
- */
- private ResourceUtils() {
- }// ResourceUtils()
-
- /**
- * Convenient method for {@link Context#getTheme()} and
- * {@link Resources.Theme#resolveAttribute(int, TypedValue, boolean)}.
- *
- * @param context
- * the context.
- * @param resId
- * The resource identifier of the desired theme attribute.
- * @return the resource ID that {@link TypedValue#resourceId} points to, or
- * {@code 0} if not found.
- */
- public static int resolveAttribute(Context context, int resId) {
- return resolveAttribute(context, resId, 0);
- }// resolveAttribute()
-
- /**
- * Convenient method for {@link Context#getTheme()} and
- * {@link Resources.Theme#resolveAttribute(int, TypedValue, boolean)}.
- *
- * @param context
- * the context.
- * @param resId
- * The resource identifier of the desired theme attribute.
- * @param defaultValue
- * the default value if cannot resolve {@code resId}.
- * @return the resource ID that {@link TypedValue#resourceId} points to, or
- * {@code defaultValue} if not found.
- */
- public static int resolveAttribute(Context context, int resId,
- int defaultValue) {
- TypedValue typedValue = new TypedValue();
- if (context.getTheme().resolveAttribute(resId, typedValue, true))
- return typedValue.resourceId;
- return defaultValue;
- }// resolveAttribute()
-
-}
diff --git a/code/src/haibison/android/lockpattern/util/SimpleWeakEncryption.java b/code/src/haibison/android/lockpattern/util/SimpleWeakEncryption.java
deleted file mode 100644
index 7de70ce..0000000
--- a/code/src/haibison/android/lockpattern/util/SimpleWeakEncryption.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern.util;
-
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.PBEKeySpec;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * The simple-and-weak encryption utilities.
- *
- * @author Hai Bison
- *
- */
-public class SimpleWeakEncryption {
-
- private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
- private static final String SECRET_KEY_FACTORY_ALGORITHM = "PBEWithMD5AndDES";
- private static final String SECRET_KEY_SPEC_ALGORITHM = "AES";
-
- private static final int KEY_LEN = 256;
- private static final int IV_LEN = 16;
- private static final int ITERATION_COUNT = 512;
- private static final char SEPARATOR = '@';
-
- public static final String UTF8 = "UTF-8";
- public static final String SHA256 = "SHA-256";
-
- /**
- * This is singleton class.
- */
- private SimpleWeakEncryption() {
- }// SimpleWeakEncryption()
-
- /**
- * Encrypts {@code data} by {@code key}.
- *
- * @param password
- * the secret key.
- * @param salt
- * the salt, can be {@code null}. But it is highly recommended
- * that you should provide it.
- * @param data
- * the data.
- * @return the encrypted data.
- * @throws RuntimeException
- * which wraps the original exception related to cipher process.
- */
- public static String encrypt(final char[] password, byte[] salt,
- final String data) {
- byte[] bytes = null;
- try {
- bytes = data.getBytes(UTF8);
- } catch (UnsupportedEncodingException e) {
- /*
- * Never catch this.
- */
- throw new RuntimeException(e);
- }
-
- Cipher cipher = null;
-
- try {
- cipher = Cipher.getInstance(TRANSFORMATION);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- } catch (NoSuchPaddingException e) {
- throw new RuntimeException(e);
- }
-
- /*
- * cipher.getIV() doesn't work the same for different API levels. So
- * we're using this technique.
- */
- final byte[] iv = SecureRandom.getSeed(IV_LEN);
-
- try {
- cipher.init(Cipher.ENCRYPT_MODE, genKey(password, salt),
- new IvParameterSpec(iv));
- } catch (InvalidKeyException e) {
- throw new RuntimeException(e);
- } catch (InvalidAlgorithmParameterException e) {
- throw new RuntimeException(e);
- }
-
- try {
- bytes = cipher.doFinal(bytes);
- return String.format("%s%s%s", Base36.toBase36(iv), SEPARATOR,
- Base36.toBase36(bytes));
- } catch (IllegalBlockSizeException e) {
- throw new RuntimeException(e);
- } catch (BadPaddingException e) {
- throw new RuntimeException(e);
- }
- }// encrypt()
-
- /**
- * Decrypts an encrypted string ({@code data}) by {@code key}.
- *
- * @param password
- * the password.
- * @param salt
- * the salt, can be {@code null}. But it is highly recommended
- * that you should provide it.
- * @param data
- * the data.
- * @return the decrypted string, or {@code null} if {@code password} is
- * invalid.
- * @throws RuntimeException
- * which wraps the original exception related to cipher process.
- */
- public static String decrypt(final char[] password, byte[] salt,
- final String data) {
- Cipher cipher = null;
- try {
- cipher = Cipher.getInstance(TRANSFORMATION);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- } catch (NoSuchPaddingException e) {
- throw new RuntimeException(e);
- }
-
- final int iSeparator = data.indexOf(SEPARATOR);
-
- try {
- cipher.init(
- Cipher.DECRYPT_MODE,
- genKey(password, salt),
- new IvParameterSpec(Base36.toBytes(data.substring(0,
- iSeparator))));
- } catch (InvalidKeyException e) {
- throw new RuntimeException(e);
- } catch (InvalidAlgorithmParameterException e) {
- throw new RuntimeException(e);
- }
-
- try {
- return new String(cipher.doFinal(Base36.toBytes(data
- .substring(iSeparator + 1))), UTF8);
- } catch (IllegalBlockSizeException e) {
- throw new RuntimeException(e);
- } catch (BadPaddingException e) {
- throw new RuntimeException(e);
- } catch (UnsupportedEncodingException e) {
- /*
- * Never catch this.
- */
- throw new RuntimeException(e);
- }
- }// decrypt()
-
- /**
- * Generates secret key.
- *
- * @param password
- * the password.
- * @param salt
- * the salt, can be {@code null}. But it is highly recommended
- * that you should provide it.
- * @return the secret key.
- * @throws RuntimeException
- * which wraps the original exception related to cipher process.
- */
- private static Key genKey(char[] password, byte[] salt) {
- SecretKeyFactory factory;
- try {
- factory = SecretKeyFactory
- .getInstance(SECRET_KEY_FACTORY_ALGORITHM);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
-
- if (salt != null && salt.length > 0)
- salt = sha256(salt);
- else
- salt = sha256(new String(password));
-
- KeySpec spec = new PBEKeySpec(password, salt, ITERATION_COUNT, KEY_LEN);
-
- SecretKey tmp = null;
- try {
- tmp = factory.generateSecret(spec);
- } catch (InvalidKeySpecException e) {
- throw new RuntimeException(e);
- }
-
- return new SecretKeySpec(sha256(tmp.getEncoded()),
- SECRET_KEY_SPEC_ALGORITHM);
- }// genKey()
-
- /**
- * Calculates SHA-256 of a string.
- *
- * @param s
- * the string.
- * @return the SHA-256 of given string.
- * @throws RuntimeException
- * which wraps {@link UnsupportedEncodingException} in case the
- * system does not support {@link #UTF8}.
- */
- public static byte[] sha256(String s) {
- try {
- return sha256(s.getBytes(UTF8));
- } catch (UnsupportedEncodingException e) {
- /*
- * Never catch this.
- */
- throw new RuntimeException(e);
- }
- }// sha256()
-
- /**
- * Calculates SHA-256 of a byte array.
- *
- * @param bytes
- * the byte array.
- * @return the SHA-256 of given data.
- * @throws RuntimeException
- * which wraps {@link NoSuchAlgorithmException} in case the
- * system does not support calculating message digest of
- * {@link #SHA256}.
- */
- public static byte[] sha256(byte[] bytes) {
- try {
- MessageDigest md = MessageDigest.getInstance(SHA256);
- md.update(bytes);
- return md.digest();
- } catch (NoSuchAlgorithmException e) {
- /*
- * Never catch this.
- */
- throw new RuntimeException(e);
- }
- }// sha256()
-
- /**
- * Base-36 utilities.
- *
- * @author Hai Bison
- *
- */
- public static class Base36 {
-
- /**
- * This is singleton class.
- */
- private Base36() {
- }// Base36()
-
- /**
- * Converts a byte array to base-36.
- *
- * @param bytes
- * the byte array.
- * @return the base-36 string representing the data given.
- */
- public static String toBase36(byte[] bytes) {
- return new BigInteger(bytes).toString(Character.MAX_RADIX);
- }// toBase36()
-
- /**
- * Converts a base-36 string to its byte array.
- *
- * @param base36
- * the base-36 string.
- * @return the original data.
- */
- public static byte[] toBytes(String base36) {
- return new BigInteger(base36, Character.MAX_RADIX).toByteArray();
- }// toBytes()
-
- }// Base36
-
-}
diff --git a/code/src/haibison/android/lockpattern/util/UI.java b/code/src/haibison/android/lockpattern/util/UI.java
deleted file mode 100644
index 8cdfffb..0000000
--- a/code/src/haibison/android/lockpattern/util/UI.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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 haibison.android.lockpattern.util;
-
-import static haibison.android.lockpattern.BuildConfig.DEBUG;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Window;
-
-/**
- * UI utilities.
- *
- * @author Hai Bison
- */
-public class UI {
-
- private static final String CLASSNAME = UI.class.getName();
-
- /**
- * The screen sizes.
- *
- * @author Hai Bison
- *
- */
- public static enum ScreenSize {
- /**
- * Small.
- */
- SMALL(1, 1, 1, 1),
- /**
- * Normal.
- */
- NORMAL(1, 1, 1, 1),
- /**
- * Large.
- */
- LARGE(.6f, .9f, .6f, .9f),
- /**
- * X-Large.
- */
- XLARGE(.6f, .9f, .5f, .7f),
- /**
- * Undefined.
- */
- UNDEFINED(1, 1, 1, 1);
-
- /**
- * The desired fixed width for a dialog along the minor axis (the screen
- * is in portrait). This is a fraction.
- */
- public final float fixedWidthMinor,
- /**
- * The desired fixed width for a dialog along the major axis (the screen
- * is in landscape). This is a fraction.
- */
- fixedWidthMajor,
- /**
- * The desired fixed height for a dialog along the minor axis (the
- * screen is in landscape). This is a fraction.
- */
- fixedHeightMinor,
- /**
- * The desired fixed height for a dialog along the major axis (the
- * screen is in portrait). This is a fraction.
- */
- fixedHeightMajor;
-
- /**
- * Creates new instance.
- *
- * @param fixedHeightMajor
- * the fixed height major.
- * @param fixedHeightMinor
- * the fixed height minor.
- * @param fixedWidthMajor
- * the fixed width major.
- * @param fixedWidthMinor
- * the fixed width minor.
- */
- private ScreenSize(float fixedHeightMajor, float fixedHeightMinor,
- float fixedWidthMajor, float fixedWidthMinor) {
- this.fixedHeightMajor = fixedHeightMajor;
- this.fixedHeightMinor = fixedHeightMinor;
- this.fixedWidthMajor = fixedWidthMajor;
- this.fixedWidthMinor = fixedWidthMinor;
- }// ScreenSize()
-
- /**
- * Gets current screen size.
- *
- * @param context
- * the context.
- * @return current screen size.
- */
- public static ScreenSize getCurrent(Context context) {
- switch (context.getResources().getConfiguration().screenLayout
- & Configuration.SCREENLAYOUT_SIZE_MASK) {
- case Configuration.SCREENLAYOUT_SIZE_SMALL:
- return SMALL;
- case Configuration.SCREENLAYOUT_SIZE_NORMAL:
- return NORMAL;
- case Configuration.SCREENLAYOUT_SIZE_LARGE:
- return LARGE;
- case Configuration.SCREENLAYOUT_SIZE_XLARGE:
- return XLARGE;
- default:
- return UNDEFINED;
- }
- }// getCurrent()
-
- }// ScreenSize
-
- /**
- * This is singleton class.
- */
- private UI() {
- }// UI
-
- /**
- * Uses a fixed size for {@code dialog} in large screens.
- *
- * @param dialog
- * the dialog.
- */
- public static void adjustDialogSizeForLargeScreens(Dialog dialog) {
- adjustDialogSizeForLargeScreens(dialog.getWindow());
- }// adjustDialogSizeForLargeScreens()
-
- /**
- * Uses a fixed size for {@code dialogWindow} in large screens.
- *
- * @param dialogWindow
- * the window of the dialog.
- */
- public static void adjustDialogSizeForLargeScreens(Window dialogWindow) {
- if (DEBUG)
- Log.d(CLASSNAME, "adjustDialogSizeForLargeScreens()");
-
- if (!dialogWindow.isFloating())
- return;
-
- final ScreenSize screenSize = ScreenSize.getCurrent(dialogWindow
- .getContext());
- switch (screenSize) {
- case LARGE:
- case XLARGE:
- break;
- default:
- return;
- }
-
- final DisplayMetrics metrics = dialogWindow.getContext().getResources()
- .getDisplayMetrics();
- final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
-
- int width = metrics.widthPixels;// dialogWindow.getDecorView().getWidth();
- int height = metrics.heightPixels;// dialogWindow.getDecorView().getHeight();
- if (DEBUG)
- Log.d(CLASSNAME,
- String.format("width = %,d | height = %,d", width, height));
-
- width = (int) (width * (isPortrait ? screenSize.fixedWidthMinor
- : screenSize.fixedWidthMajor));
- height = (int) (height * (isPortrait ? screenSize.fixedHeightMajor
- : screenSize.fixedHeightMinor));
-
- if (DEBUG)
- Log.d(CLASSNAME, String.format(
- "NEW >>> width = %,d | height = %,d", width, height));
- dialogWindow.setLayout(width, height);
- }// adjustDialogSizeForLargeScreens()
-
-}
diff --git a/code/src/haibison/android/lockpattern/widget/LockPatternUtils.java b/code/src/haibison/android/lockpattern/widget/LockPatternUtils.java
deleted file mode 100644
index 2edde89..0000000
--- a/code/src/haibison/android/lockpattern/widget/LockPatternUtils.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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 haibison.android.lockpattern.widget;
-
-import static haibison.android.lockpattern.BuildConfig.DEBUG;
-import haibison.android.lockpattern.collect.Lists;
-import haibison.android.lockpattern.util.Randoms;
-
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-import android.util.Log;
-
-/**
- * Utilities for the lock pattern and its settings.
- */
-public class LockPatternUtils {
-
- /**
- * Used for debugging...
- */
- private static final String CLASSNAME = LockPatternUtils.class.getName();
-
- /**
- * "UTF-8"
- */
- public static final String UTF8 = "UTF-8";
-
- /**
- * "SHA-1"
- */
- public static final String SHA1 = "SHA-1";
-
- /**
- * This is singleton class.
- */
- private LockPatternUtils() {
- }// LockPatternUtils
-
- /**
- * Deserialize a pattern.
- *
- * @param string
- * The pattern serialized with {@link #patternToString}
- * @return The pattern.
- */
- public static List stringToPattern(String string) {
- List result = Lists.newArrayList();
-
- try {
- final byte[] bytes = string.getBytes(UTF8);
- for (int i = 0; i < bytes.length; i++) {
- byte b = bytes[i];
- result.add(LockPatternView.Cell.of(b / 3, b % 3));
- }
- } catch (UnsupportedEncodingException e) {
- // never catch this
- }
-
- return result;
- }// stringToPattern()
-
- /**
- * Serialize a pattern.
- *
- * @param pattern
- * The pattern.
- * @return The pattern in string form.
- */
- public static String patternToString(List pattern) {
- if (pattern == null) {
- return "";
- }
- final int patternSize = pattern.size();
-
- byte[] res = new byte[patternSize];
- for (int i = 0; i < patternSize; i++) {
- LockPatternView.Cell cell = pattern.get(i);
- res[i] = (byte) (cell.row * 3 + cell.column);
- }
- try {
- return new String(res, UTF8);
- } catch (UnsupportedEncodingException e) {
- // never catch this
- return "";
- }
- }// patternToString()
-
- /**
- * Serializes a pattern
- *
- * @param pattern
- * The pattern
- * @return The SHA-1 string of the pattern got from
- * {@link #patternToString(List)}
- */
- public static String patternToSha1(List pattern) {
- try {
- MessageDigest md = MessageDigest.getInstance(SHA1);
- md.update(patternToString(pattern).getBytes(UTF8));
-
- byte[] digest = md.digest();
- BigInteger bi = new BigInteger(1, digest);
- return String.format((Locale) null,
- "%0" + (digest.length * 2) + "x", bi).toLowerCase();
- } catch (NoSuchAlgorithmException e) {
- // never catch this
- return "";
- } catch (UnsupportedEncodingException e) {
- // never catch this
- return "";
- }
- }// patternToSha1()
-
- /**
- * Generates a random "CAPTCHA" pattern. By saying "CAPTCHA", this method
- * ensures that the generated pattern is easy for the user to re-draw.
- *
- * Notes: This method is not optimized and not
- * benchmarked yet for large size of the pattern's matrix. Currently it
- * works fine with a matrix of {@code 3x3} cells. Be careful when the size
- * increases.
- *
- *
- * @param size
- * the size of the pattern to be generated.
- * @return the generated pattern.
- * @throws IndexOutOfBoundsException
- * if {@code size <= 0} or {@code size > }
- * {@link LockPatternView#MATRIX_SIZE}.
- * @since v2.7 beta
- * @author Hai Bison
- */
- public static ArrayList genCaptchaPattern(int size)
- throws IndexOutOfBoundsException {
- if (size <= 0 || size > LockPatternView.MATRIX_SIZE)
- throw new IndexOutOfBoundsException(
- "`size` must be in range [1, `LockPatternView.MATRIX_SIZE`]");
-
- final List usedIds = Lists.newArrayList();
- int lastId = Randoms.randInt(LockPatternView.MATRIX_SIZE);
- usedIds.add(lastId);
-
- while (usedIds.size() < size) {
- /*
- * We start from an empty matrix, so there's always a break point to
- * exit this loop.
- */
-
- if (DEBUG)
- Log.d(CLASSNAME, " >> lastId = " + lastId);
-
- final int lastRow = lastId / LockPatternView.MATRIX_WIDTH;
- final int lastCol = lastId % LockPatternView.MATRIX_WIDTH;
-
- /*
- * This is the max available rows/ columns that we can reach from
- * the cell of `lastId` to the border of the matrix.
- */
- final int maxDistance = Math.max(
- Math.max(lastRow, LockPatternView.MATRIX_WIDTH - lastRow),
- Math.max(lastCol, LockPatternView.MATRIX_WIDTH - lastCol));
-
- lastId = -1;
-
- /*
- * Starting from `distance` = 1, find the closest-available
- * neighbour value of the cell [lastRow, lastCol].
- */
- for (int distance = 1; distance <= maxDistance; distance++) {
- /*
- * Now we have a square surrounding the current cell. We call it
- * ABCD, in which A is top-left, and C is bottom-right.
- */
-
- final int rowA = lastRow - distance;
- final int colA = lastCol - distance;
- final int rowC = lastRow + distance;
- final int colC = lastCol + distance;
-
- int[] randomValues;
-
- /*
- * Process randomly AB, BC, CD, and DA. Break the loop as soon
- * as we find one value.
- */
- final int[] lines = Randoms.randIntArray(4);
- for (int line : lines) {
- switch (line) {
- case 0: {
- if (rowA >= 0) {
- randomValues = Randoms.randIntArray(Math.max(0,
- colA), Math.min(
- LockPatternView.MATRIX_WIDTH, colC + 1));
- for (int c : randomValues) {
- lastId = rowA * LockPatternView.MATRIX_WIDTH
- + c;
- if (usedIds.contains(lastId))
- lastId = -1;
- else
- break;
- }
- }
- break;
- }// AB
- case 1: {
- if (colC < LockPatternView.MATRIX_WIDTH) {
- randomValues = Randoms.randIntArray(Math.max(0,
- rowA + 1), Math.min(
- LockPatternView.MATRIX_WIDTH, rowC + 1));
- for (int r : randomValues) {
- lastId = r * LockPatternView.MATRIX_WIDTH
- + colC;
- if (usedIds.contains(lastId))
- lastId = -1;
- else
- break;
- }
- }
- break;
- }// BC
- case 2: {
- if (rowC < LockPatternView.MATRIX_WIDTH) {
- randomValues = Randoms.randIntArray(Math.max(0,
- colA), Math.min(
- LockPatternView.MATRIX_WIDTH, colC));
- for (int c : randomValues) {
- lastId = rowC * LockPatternView.MATRIX_WIDTH
- + c;
- if (usedIds.contains(lastId))
- lastId = -1;
- else
- break;
- }
- }
- break;
- }// DC
- case 3: {
- if (colA >= 0) {
- randomValues = Randoms.randIntArray(Math.max(0,
- rowA + 1), Math.min(
- LockPatternView.MATRIX_WIDTH, rowC));
- for (int r : randomValues) {
- lastId = r * LockPatternView.MATRIX_WIDTH
- + colA;
- if (usedIds.contains(lastId))
- lastId = -1;
- else
- break;
- }
- }
- break;
- }// AD
- }
-
- if (lastId >= 0)
- break;
- }// for line
-
- if (lastId >= 0)
- break;
- }// for distance
-
- usedIds.add(lastId);
- }// while
-
- final ArrayList result = Lists.newArrayList();
- for (int id : usedIds)
- result.add(LockPatternView.Cell.of(id));
-
- return result;
- }// genCaptchaPattern()
-
-}
diff --git a/code/src/haibison/android/lockpattern/widget/LockPatternView.java b/code/src/haibison/android/lockpattern/widget/LockPatternView.java
deleted file mode 100644
index 8822a69..0000000
--- a/code/src/haibison/android/lockpattern/widget/LockPatternView.java
+++ /dev/null
@@ -1,1369 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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 haibison.android.lockpattern.widget;
-
-import haibison.android.lockpattern.R;
-import haibison.android.lockpattern.util.FloatAnimator;
-import haibison.android.lockpattern.util.ResourceUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.Debug;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.view.HapticFeedbackConstants;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-/**
- * Displays and detects the user's unlock attempt, which is a drag of a finger
- * across 9 regions of the screen.
- *
- * Is also capable of displaying a static pattern in "in progress", "wrong" or
- * "correct" states.
- */
-public class LockPatternView extends View {
-
- /**
- * Represents a cell in the MATRIX_WIDTH x MATRIX_WIDTH matrix of the unlock
- * pattern view.
- */
- public static class Cell implements Parcelable {
-
- /**
- * Row.
- */
- public final int row;
-
- /**
- * Column.
- */
- public final int column;
-
- /*
- * keep # objects limited to MATRIX_SIZE
- */
- static Cell[][] sCells = new Cell[MATRIX_WIDTH][MATRIX_WIDTH];
- static {
- for (int i = 0; i < MATRIX_WIDTH; i++) {
- for (int j = 0; j < MATRIX_WIDTH; j++) {
- sCells[i][j] = new Cell(i, j);
- }
- }
- }
-
- /**
- * @param row
- * The row of the cell.
- * @param column
- * The column of the cell.
- */
- private Cell(int row, int column) {
- checkRange(row, column);
- this.row = row;
- this.column = column;
- }
-
- /**
- * Gets the ID.It is counted from left to right, top to bottom of the
- * matrix, starting by zero.
- *
- * @return the ID.
- */
- public int getId() {
- return row * MATRIX_WIDTH + column;
- }// getId()
-
- /**
- * @param row
- * The row of the cell.
- * @param column
- * The column of the cell.
- */
- public static synchronized Cell of(int row, int column) {
- checkRange(row, column);
- return sCells[row][column];
- }
-
- /**
- * Gets a cell from its ID.
- *
- * @param id
- * the cell ID.
- * @return the cell.
- * @since v2.7 beta
- * @author Hai Bison
- */
- public static synchronized Cell of(int id) {
- return of(id / MATRIX_WIDTH, id % MATRIX_WIDTH);
- }// of()
-
- private static void checkRange(int row, int column) {
- if (row < 0 || row > MATRIX_WIDTH - 1) {
- throw new IllegalArgumentException("row must be in range 0-"
- + (MATRIX_WIDTH - 1));
- }
- if (column < 0 || column > MATRIX_WIDTH - 1) {
- throw new IllegalArgumentException("column must be in range 0-"
- + (MATRIX_WIDTH - 1));
- }
- }
-
- @Override
- public String toString() {
- return "(ROW=" + row + ",COL=" + column + ")";
- }// toString()
-
- @Override
- public boolean equals(Object object) {
- if (object instanceof Cell)
- return column == ((Cell) object).column
- && row == ((Cell) object).row;
- return super.equals(object);
- }// equals()
-
- /*
- * PARCELABLE
- */
-
- @Override
- public int describeContents() {
- return 0;
- }// describeContents()
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(column);
- dest.writeInt(row);
- }// writeToParcel()
-
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
-
- public Cell createFromParcel(Parcel in) {
- return new Cell(in);
- }// createFromParcel()
-
- public Cell[] newArray(int size) {
- return new Cell[size];
- }// newArray()
- };// CREATOR
-
- private Cell(Parcel in) {
- column = in.readInt();
- row = in.readInt();
- }// Cell()
-
- }// Cell
-
- /**
- * How to display the current pattern.
- */
- public enum DisplayMode {
-
- /**
- * The pattern drawn is correct (i.e draw it in a friendly color)
- */
- Correct,
-
- /**
- * Animate the pattern (for demo, and help).
- */
- Animate,
-
- /**
- * The pattern is wrong (i.e draw a foreboding color)
- */
- Wrong
- }
-
- /**
- * The call back interface for detecting patterns entered by the user.
- */
- public static interface OnPatternListener {
-
- /**
- * A new pattern has begun.
- */
- void onPatternStart();
-
- /**
- * The pattern was cleared.
- */
- void onPatternCleared();
-
- /**
- * The user extended the pattern currently being drawn by one cell.
- *
- * @param pattern
- * The pattern with newly added cell.
- */
- void onPatternCellAdded(List pattern);
-
- /**
- * A pattern was detected from the user.
- *
- * @param pattern
- * The pattern.
- */
- void onPatternDetected(List pattern);
- }
-
- // Aspect to use when rendering this view
- private static final int ASPECT_SQUARE = 0; // View will be the minimum of
- // width/height
- private static final int ASPECT_LOCK_WIDTH = 1; // Fixed width; height will
- // be minimum of (w,h)
- private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will
- // be minimum of (w,h)
-
- /**
- * This is the width of the matrix (the number of dots per row and column).
- * Change this value to change the dimension of the pattern's matrix.
- *
- * @since v2.7 beta
- * @author Thomas Breitbach
- */
- public static final int MATRIX_WIDTH = 3;
-
- /**
- * The size of the pattern's matrix.
- */
- public static final int MATRIX_SIZE = MATRIX_WIDTH * MATRIX_WIDTH;
-
- private static final boolean PROFILE_DRAWING = false;
- private final CellState[][] mCellStates;
-
- private final int mDotSize;
- private final int mDotSizeActivated;
- private final int mPathWidth;
-
- private boolean mDrawingProfilingStarted = false;
-
- private Paint mPaint = new Paint();
- private Paint mPathPaint = new Paint();
-
- /**
- * How many milliseconds we spend animating each circle of a lock pattern if
- * the animating mode is set. The entire animation should take this constant
- * * the length of the pattern to complete.
- */
- private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
-
- /**
- * This can be used to avoid updating the display for very small motions or
- * noisy panels. It didn't seem to have much impact on the devices tested,
- * so currently set to 0.
- */
- private static final float DRAG_THRESHHOLD = 0.0f;
-
- private OnPatternListener mOnPatternListener;
- private ArrayList mPattern = new ArrayList(MATRIX_SIZE);
-
- /**
- * Lookup table for the circles of the pattern we are currently drawing.
- * This will be the cells of the complete pattern unless we are animating,
- * in which case we use this to hold the cells we are drawing for the in
- * progress animation.
- */
- private boolean[][] mPatternDrawLookup = new boolean[MATRIX_WIDTH][MATRIX_WIDTH];
-
- /**
- * the in progress point: - during interaction: where the user's finger is -
- * during animation: the current tip of the animating line
- */
- private float mInProgressX = -1;
- private float mInProgressY = -1;
-
- private long mAnimatingPeriodStart;
-
- private DisplayMode mPatternDisplayMode = DisplayMode.Correct;
- private boolean mInputEnabled = true;
- private boolean mInStealthMode = false;
- private boolean mEnableHapticFeedback = true;
- private boolean mPatternInProgress = false;
-
- private float mHitFactor = 0.6f;
-
- private float mSquareWidth;
- private float mSquareHeight;
-
- private final Path mCurrentPath = new Path();
- private final Rect mInvalidate = new Rect();
- private final Rect mTmpInvalidateRect = new Rect();
-
- private int mAspect;
- private int mRegularColor;
- private int mErrorColor;
- private int mSuccessColor;
-
- private Interpolator mFastOutSlowInInterpolator;
- private Interpolator mLinearOutSlowInInterpolator;
-
- public static class CellState {
-
- public float scale = 1.0f;
- public float translateY = 0.0f;
- public float alpha = 1.0f;
- public float size;
- public float lineEndX = Float.MIN_VALUE;
- public float lineEndY = Float.MIN_VALUE;
- public ValueAnimator lineAnimator;
- }
-
- public LockPatternView(Context context) {
- this(context, null);
- }
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public LockPatternView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.Alp_42447968_LockPatternView);
-
- final String aspect = a
- .getString(R.styleable.Alp_42447968_LockPatternView_aspect);
-
- if ("square".equals(aspect)) {
- mAspect = ASPECT_SQUARE;
- } else if ("lock_width".equals(aspect)) {
- mAspect = ASPECT_LOCK_WIDTH;
- } else if ("lock_height".equals(aspect)) {
- mAspect = ASPECT_LOCK_HEIGHT;
- } else {
- mAspect = ASPECT_SQUARE;
- }
-
- setClickable(true);
-
- mPathPaint.setAntiAlias(true);
- mPathPaint.setDither(true);
-
- mRegularColor = getResources().getColor(
- ResourceUtils.resolveAttribute(getContext(),
- R.attr.alp_42447968_color_lock_pattern_view_regular));
- mErrorColor = getResources().getColor(
- ResourceUtils.resolveAttribute(getContext(),
- R.attr.alp_42447968_color_lock_pattern_view_error));
- mSuccessColor = getResources().getColor(
- ResourceUtils.resolveAttribute(getContext(),
- R.attr.alp_42447968_color_lock_pattern_view_success));
-
- mRegularColor = a.getColor(
- R.styleable.Alp_42447968_LockPatternView_regularColor,
- mRegularColor);
- mErrorColor = a.getColor(
- R.styleable.Alp_42447968_LockPatternView_errorColor,
- mErrorColor);
- mSuccessColor = a.getColor(
- R.styleable.Alp_42447968_LockPatternView_successColor,
- mSuccessColor);
-
- int pathColor = a.getColor(
- R.styleable.Alp_42447968_LockPatternView_pathColor,
- mRegularColor);
- mPathPaint.setColor(pathColor);
-
- mPathPaint.setStyle(Paint.Style.STROKE);
- mPathPaint.setStrokeJoin(Paint.Join.ROUND);
- mPathPaint.setStrokeCap(Paint.Cap.ROUND);
-
- mPathWidth = getResources().getDimensionPixelSize(
- R.dimen.alp_42447968_lock_pattern_dot_line_width);
- mPathPaint.setStrokeWidth(mPathWidth);
-
- mDotSize = getResources().getDimensionPixelSize(
- R.dimen.alp_42447968_lock_pattern_dot_size);
- mDotSizeActivated = getResources().getDimensionPixelSize(
- R.dimen.alp_42447968_lock_pattern_dot_size_activated);
-
- mPaint.setAntiAlias(true);
- mPaint.setDither(true);
-
- mCellStates = new CellState[MATRIX_WIDTH][MATRIX_WIDTH];
- for (int i = 0; i < MATRIX_WIDTH; i++) {
- for (int j = 0; j < MATRIX_WIDTH; j++) {
- mCellStates[i][j] = new CellState();
- mCellStates[i][j].size = mDotSize;
- }
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
- && !isInEditMode()) {
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- context, android.R.interpolator.fast_out_slow_in);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- context, android.R.interpolator.linear_out_slow_in);
- }// if
- }// LockPatternView()
-
- public CellState[][] getCellStates() {
- return mCellStates;
- }
-
- /**
- * @return Whether the view is in stealth mode.
- */
- public boolean isInStealthMode() {
- return mInStealthMode;
- }
-
- /**
- * @return Whether the view has tactile feedback enabled.
- */
- public boolean isTactileFeedbackEnabled() {
- return mEnableHapticFeedback;
- }
-
- /**
- * Set whether the view is in stealth mode. If {@code true}, there will be
- * no visible feedback as the user enters the pattern.
- *
- * @param inStealthMode
- * Whether in stealth mode.
- */
- public void setInStealthMode(boolean inStealthMode) {
- mInStealthMode = inStealthMode;
- }
-
- /**
- * Set whether the view will use tactile feedback. If {@code true}, there
- * will be tactile feedback as the user enters the pattern.
- *
- * @param tactileFeedbackEnabled
- * Whether tactile feedback is enabled
- */
- public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) {
- mEnableHapticFeedback = tactileFeedbackEnabled;
- }
-
- /**
- * Set the call back for pattern detection.
- *
- * @param onPatternListener
- * The call back.
- */
- public void setOnPatternListener(OnPatternListener onPatternListener) {
- mOnPatternListener = onPatternListener;
- }
-
- /**
- * Retrieves current pattern.
- *
- * @return current displaying pattern. Note: This is an independent
- * list with the view's pattern itself.
- */
- @SuppressWarnings("unchecked")
- public List getPattern() {
- return (List) mPattern.clone();
- }// getPattern()
-
- /**
- * Set the pattern explicitely (rather than waiting for the user to input a
- * pattern).
- *
- * @param displayMode
- * How to display the pattern.
- * @param pattern
- * The pattern.
- */
- public void setPattern(DisplayMode displayMode, List pattern) {
- mPattern.clear();
- mPattern.addAll(pattern);
- clearPatternDrawLookup();
- for (Cell cell : pattern) {
- mPatternDrawLookup[cell.row][cell.column] = true;
- }
-
- setDisplayMode(displayMode);
- }
-
- /**
- * Gets display mode.
- *
- * @return display mode.
- */
- public DisplayMode getDisplayMode() {
- return mPatternDisplayMode;
- }// getDisplayMode()
-
- /**
- * Set the display mode of the current pattern. This can be useful, for
- * instance, after detecting a pattern to tell this view whether change the
- * in progress result to correct or wrong.
- *
- * @param displayMode
- * The display mode.
- */
- public void setDisplayMode(DisplayMode displayMode) {
- mPatternDisplayMode = displayMode;
- if (displayMode == DisplayMode.Animate) {
- if (mPattern.size() == 0) {
- throw new IllegalStateException(
- "you must have a pattern to "
- + "animate if you want to set the display mode to animate");
- }
- mAnimatingPeriodStart = SystemClock.elapsedRealtime();
- final Cell first = mPattern.get(0);
- mInProgressX = getCenterXForColumn(first.column);
- mInProgressY = getCenterYForRow(first.row);
- clearPatternDrawLookup();
- }
- invalidate();
- }
-
- private void notifyCellAdded() {
- sendAccessEvent(R.string.alp_42447968_lockscreen_access_pattern_cell_added);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternCellAdded(mPattern);
- }
- }
-
- private void notifyPatternStarted() {
- sendAccessEvent(R.string.alp_42447968_lockscreen_access_pattern_start);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternStart();
- }
- }
-
- private void notifyPatternDetected() {
- sendAccessEvent(R.string.alp_42447968_lockscreen_access_pattern_detected);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternDetected(mPattern);
- }
- }
-
- private void notifyPatternCleared() {
- sendAccessEvent(R.string.alp_42447968_lockscreen_access_pattern_cleared);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternCleared();
- }
- }
-
- /**
- * Clear the pattern.
- */
- public void clearPattern() {
- resetPattern();
- }
-
- /**
- * Reset all pattern state.
- */
- private void resetPattern() {
- mPattern.clear();
- clearPatternDrawLookup();
- mPatternDisplayMode = DisplayMode.Correct;
- invalidate();
- }
-
- /**
- * Clear the pattern lookup table.
- */
- private void clearPatternDrawLookup() {
- for (int i = 0; i < MATRIX_WIDTH; i++) {
- for (int j = 0; j < MATRIX_WIDTH; j++) {
- mPatternDrawLookup[i][j] = false;
- }
- }
- }
-
- /**
- * Disable input (for instance when displaying a message that will timeout
- * so user doesn't get view into messy state).
- */
- public void disableInput() {
- mInputEnabled = false;
- }
-
- /**
- * Enable input.
- */
- public void enableInput() {
- mInputEnabled = true;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- final int width = w - getPaddingLeft() - getPaddingRight();
- mSquareWidth = width / (float) MATRIX_WIDTH;
-
- final int height = h - getPaddingTop() - getPaddingBottom();
- mSquareHeight = height / (float) MATRIX_WIDTH;
- }
-
- private int resolveMeasured(int measureSpec, int desired) {
- int result = 0;
- int specSize = MeasureSpec.getSize(measureSpec);
- switch (MeasureSpec.getMode(measureSpec)) {
- case MeasureSpec.UNSPECIFIED:
- result = desired;
- break;
- case MeasureSpec.AT_MOST:
- result = Math.max(specSize, desired);
- break;
- case MeasureSpec.EXACTLY:
- default:
- result = specSize;
- }
- return result;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int minimumWidth = getSuggestedMinimumWidth();
- final int minimumHeight = getSuggestedMinimumHeight();
- int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
- int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
-
- switch (mAspect) {
- case ASPECT_SQUARE:
- viewWidth = viewHeight = Math.min(viewWidth, viewHeight);
- break;
- case ASPECT_LOCK_WIDTH:
- viewHeight = Math.min(viewWidth, viewHeight);
- break;
- case ASPECT_LOCK_HEIGHT:
- viewWidth = Math.min(viewWidth, viewHeight);
- break;
- }
- // Log.v(TAG, "LockPatternView dimensions: " + viewWidth + "x" +
- // viewHeight);
- setMeasuredDimension(viewWidth, viewHeight);
- }
-
- /**
- * Determines whether the point x, y will add a new point to the current
- * pattern (in addition to finding the cell, also makes heuristic choices
- * such as filling in gaps based on current pattern).
- *
- * @param x
- * The x coordinate.
- * @param y
- * The y coordinate.
- */
- @TargetApi(Build.VERSION_CODES.ECLAIR)
- private Cell detectAndAddHit(float x, float y) {
- final Cell cell = checkForNewHit(x, y);
- if (cell != null) {
-
- // check for gaps in existing pattern
- Cell fillInGapCell = null;
- final ArrayList pattern = mPattern;
- if (!pattern.isEmpty()) {
- final Cell lastCell = pattern.get(pattern.size() - 1);
- int dRow = cell.row - lastCell.row;
- int dColumn = cell.column - lastCell.column;
-
- int fillInRow = lastCell.row;
- int fillInColumn = lastCell.column;
-
- if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) {
- fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1);
- }
-
- if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) {
- fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1);
- }
-
- fillInGapCell = Cell.of(fillInRow, fillInColumn);
- }
-
- if (fillInGapCell != null
- && !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
- addCellToPattern(fillInGapCell);
- }
- addCellToPattern(cell);
- if (mEnableHapticFeedback) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR)
- performHapticFeedback(
- HapticFeedbackConstants.VIRTUAL_KEY,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
- | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
- }
- return cell;
- }
- return null;
- }
-
- private void addCellToPattern(Cell newCell) {
- mPatternDrawLookup[newCell.row][newCell.column] = true;
- mPattern.add(newCell);
- if (!mInStealthMode) {
- startCellActivatedAnimation(newCell);
- }
- notifyCellAdded();
- }
-
- private void startCellActivatedAnimation(Cell cell) {
- final CellState cellState = mCellStates[cell.row][cell.column];
- startSizeAnimation(mDotSize, mDotSizeActivated, 96,
- mLinearOutSlowInInterpolator, cellState, new Runnable() {
-
- @Override
- public void run() {
- startSizeAnimation(mDotSizeActivated, mDotSize, 192,
- mFastOutSlowInInterpolator, cellState, null);
- }
- });
- startLineEndAnimation(cellState, mInProgressX, mInProgressY,
- getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
- }
-
- private void startLineEndAnimation(final CellState state,
- final float startX, final float startY, final float targetX,
- final float targetY) {
- /*
- * Currently this animation looks unclear, we don't really need it...
- */
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
- return;
-
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
- valueAnimator
- .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float t = (Float) animation.getAnimatedValue();
- state.lineEndX = (1 - t) * startX + t * targetX;
- state.lineEndY = (1 - t) * startY + t * targetY;
- invalidate();
- }
-
- });
- valueAnimator.addListener(new AnimatorListenerAdapter() {
-
- @Override
- public void onAnimationEnd(Animator animation) {
- state.lineAnimator = null;
- }
-
- });
- valueAnimator.setInterpolator(mFastOutSlowInInterpolator);
- valueAnimator.setDuration(100);
- valueAnimator.start();
- state.lineAnimator = valueAnimator;
- }
-
- private void startSizeAnimation(float start, float end, long duration,
- Interpolator interpolator, final CellState state,
- final Runnable endRunnable) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
- FloatAnimator animator = new FloatAnimator(start, end, duration);
- animator.addEventListener(new FloatAnimator.SimpleEventListener() {
-
- @Override
- public void onAnimationUpdate(FloatAnimator animator) {
- state.size = (Float) animator.getAnimatedValue();
- invalidate();
- }// onAnimationUpdate()
-
- @Override
- public void onAnimationEnd(FloatAnimator animator) {
- if (endRunnable != null)
- endRunnable.run();
- }// onAnimationEnd()
-
- });
- animator.start();
- }// API < 11
- else {
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
- valueAnimator
- .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- state.size = (Float) animation.getAnimatedValue();
- invalidate();
- }
-
- });
- if (endRunnable != null) {
- valueAnimator.addListener(new AnimatorListenerAdapter() {
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (endRunnable != null)
- endRunnable.run();
- }
-
- });
- }
- valueAnimator.setInterpolator(interpolator);
- valueAnimator.setDuration(duration);
- valueAnimator.start();
- }// API 11+
- }// startSizeAnimation()
-
- // helper method to find which cell a point maps to
- private Cell checkForNewHit(float x, float y) {
-
- final int rowHit = getRowHit(y);
- if (rowHit < 0) {
- return null;
- }
- final int columnHit = getColumnHit(x);
- if (columnHit < 0) {
- return null;
- }
-
- if (mPatternDrawLookup[rowHit][columnHit]) {
- return null;
- }
- return Cell.of(rowHit, columnHit);
- }
-
- /**
- * Helper method to find the row that y falls into.
- *
- * @param y
- * The y coordinate
- * @return The row that y falls in, or -1 if it falls in no row.
- */
- private int getRowHit(float y) {
-
- final float squareHeight = mSquareHeight;
- float hitSize = squareHeight * mHitFactor;
-
- float offset = getPaddingTop() + (squareHeight - hitSize) / 2f;
- for (int i = 0; i < MATRIX_WIDTH; i++) {
-
- final float hitTop = offset + squareHeight * i;
- if (y >= hitTop && y <= hitTop + hitSize) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Helper method to find the column x fallis into.
- *
- * @param x
- * The x coordinate.
- * @return The column that x falls in, or -1 if it falls in no column.
- */
- private int getColumnHit(float x) {
- final float squareWidth = mSquareWidth;
- float hitSize = squareWidth * mHitFactor;
-
- float offset = getPaddingLeft() + (squareWidth - hitSize) / 2f;
- for (int i = 0; i < MATRIX_WIDTH; i++) {
-
- final float hitLeft = offset + squareWidth * i;
- if (x >= hitLeft && x <= hitLeft + hitSize) {
- return i;
- }
- }
- return -1;
- }
-
- @Override
- public boolean onHoverEvent(MotionEvent event) {
- if (((AccessibilityManager) getContext().getSystemService(
- Context.ACCESSIBILITY_SERVICE)).isTouchExplorationEnabled()) {
- final int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_HOVER_ENTER:
- event.setAction(MotionEvent.ACTION_DOWN);
- break;
- case MotionEvent.ACTION_HOVER_MOVE:
- event.setAction(MotionEvent.ACTION_MOVE);
- break;
- case MotionEvent.ACTION_HOVER_EXIT:
- event.setAction(MotionEvent.ACTION_UP);
- break;
- }
- onTouchEvent(event);
- event.setAction(action);
- }
- return super.onHoverEvent(event);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!mInputEnabled || !isEnabled()) {
- return false;
- }
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- handleActionDown(event);
- return true;
- case MotionEvent.ACTION_UP:
- handleActionUp(event);
- return true;
- case MotionEvent.ACTION_MOVE:
- handleActionMove(event);
- return true;
- case MotionEvent.ACTION_CANCEL:
- /*
- * Original source check for mPatternInProgress == true first before
- * calling next three lines. But if we do that, there will be
- * nothing happened when the user taps at empty area and releases
- * the finger. We want the pattern to be reset and the message will
- * be updated after the user did that.
- */
- mPatternInProgress = false;
- resetPattern();
- notifyPatternCleared();
-
- if (PROFILE_DRAWING) {
- if (mDrawingProfilingStarted) {
- Debug.stopMethodTracing();
- mDrawingProfilingStarted = false;
- }
- }
- return true;
- }
- return false;
- }
-
- private void handleActionMove(MotionEvent event) {
- // Handle all recent motion events so we don't skip any cells even when
- // the device
- // is busy...
- final float radius = mPathWidth;
- final int historySize = event.getHistorySize();
- mTmpInvalidateRect.setEmpty();
- boolean invalidateNow = false;
- for (int i = 0; i < historySize + 1; i++) {
- final float x = i < historySize ? event.getHistoricalX(i) : event
- .getX();
- final float y = i < historySize ? event.getHistoricalY(i) : event
- .getY();
- Cell hitCell = detectAndAddHit(x, y);
- final int patternSize = mPattern.size();
- if (hitCell != null && patternSize == 1) {
- mPatternInProgress = true;
- notifyPatternStarted();
- }
- // note current x and y for rubber banding of in progress patterns
- final float dx = Math.abs(x - mInProgressX);
- final float dy = Math.abs(y - mInProgressY);
- if (dx > DRAG_THRESHHOLD || dy > DRAG_THRESHHOLD) {
- invalidateNow = true;
- }
-
- if (mPatternInProgress && patternSize > 0) {
- final ArrayList pattern = mPattern;
- final Cell lastCell = pattern.get(patternSize - 1);
- float lastCellCenterX = getCenterXForColumn(lastCell.column);
- float lastCellCenterY = getCenterYForRow(lastCell.row);
-
- // Adjust for drawn segment from last cell to (x,y). Radius
- // accounts for line width.
- float left = Math.min(lastCellCenterX, x) - radius;
- float right = Math.max(lastCellCenterX, x) + radius;
- float top = Math.min(lastCellCenterY, y) - radius;
- float bottom = Math.max(lastCellCenterY, y) + radius;
-
- // Invalidate between the pattern's new cell and the pattern's
- // previous cell
- if (hitCell != null) {
- final float width = mSquareWidth * 0.5f;
- final float height = mSquareHeight * 0.5f;
- final float hitCellCenterX = getCenterXForColumn(hitCell.column);
- final float hitCellCenterY = getCenterYForRow(hitCell.row);
-
- left = Math.min(hitCellCenterX - width, left);
- right = Math.max(hitCellCenterX + width, right);
- top = Math.min(hitCellCenterY - height, top);
- bottom = Math.max(hitCellCenterY + height, bottom);
- }
-
- // Invalidate between the pattern's last cell and the previous
- // location
- mTmpInvalidateRect.union(Math.round(left), Math.round(top),
- Math.round(right), Math.round(bottom));
- }
- }
- mInProgressX = event.getX();
- mInProgressY = event.getY();
-
- // To save updates, we only invalidate if the user moved beyond a
- // certain amount.
- if (invalidateNow) {
- mInvalidate.union(mTmpInvalidateRect);
- invalidate(mInvalidate);
- mInvalidate.set(mTmpInvalidateRect);
- }
- }
-
- private void sendAccessEvent(int resId) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
- setContentDescription(getContext().getString(resId));
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
- setContentDescription(null);
- } else
- announceForAccessibility(getContext().getString(resId));
- }
-
- private void handleActionUp(MotionEvent event) {
- // report pattern detected
- if (!mPattern.isEmpty()) {
- mPatternInProgress = false;
- cancelLineAnimations();
- notifyPatternDetected();
- invalidate();
- }
- if (PROFILE_DRAWING) {
- if (mDrawingProfilingStarted) {
- Debug.stopMethodTracing();
- mDrawingProfilingStarted = false;
- }
- }
- }
-
- private void cancelLineAnimations() {
- for (int i = 0; i < MATRIX_WIDTH; i++) {
- for (int j = 0; j < MATRIX_WIDTH; j++) {
- CellState state = mCellStates[i][j];
- if (state.lineAnimator != null) {
- state.lineAnimator.cancel();
- state.lineEndX = Float.MIN_VALUE;
- state.lineEndY = Float.MIN_VALUE;
- }
- }
- }
- }
-
- private void handleActionDown(MotionEvent event) {
- resetPattern();
- final float x = event.getX();
- final float y = event.getY();
- final Cell hitCell = detectAndAddHit(x, y);
- if (hitCell != null) {
- mPatternInProgress = true;
- mPatternDisplayMode = DisplayMode.Correct;
- notifyPatternStarted();
- } else {
- /*
- * Original source check for mPatternInProgress == true first before
- * calling this block. But if we do that, there will be nothing
- * happened when the user taps at empty area and releases the
- * finger. We want the pattern to be reset and the message will be
- * updated after the user did that.
- */
- mPatternInProgress = false;
- notifyPatternCleared();
- }
- if (hitCell != null) {
- final float startX = getCenterXForColumn(hitCell.column);
- final float startY = getCenterYForRow(hitCell.row);
-
- final float widthOffset = mSquareWidth / 2f;
- final float heightOffset = mSquareHeight / 2f;
-
- invalidate((int) (startX - widthOffset),
- (int) (startY - heightOffset),
- (int) (startX + widthOffset), (int) (startY + heightOffset));
- }
- mInProgressX = x;
- mInProgressY = y;
- if (PROFILE_DRAWING) {
- if (!mDrawingProfilingStarted) {
- Debug.startMethodTracing("LockPatternDrawing");
- mDrawingProfilingStarted = true;
- }
- }
- }
-
- private float getCenterXForColumn(int column) {
- return getPaddingLeft() + column * mSquareWidth + mSquareWidth / 2f;
- }
-
- private float getCenterYForRow(int row) {
- return getPaddingTop() + row * mSquareHeight + mSquareHeight / 2f;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- final ArrayList pattern = mPattern;
- final int count = pattern.size();
- final boolean[][] drawLookup = mPatternDrawLookup;
-
- if (mPatternDisplayMode == DisplayMode.Animate) {
-
- // figure out which circles to draw
-
- // + 1 so we pause on complete pattern
- final int oneCycle = (count + 1) * MILLIS_PER_CIRCLE_ANIMATING;
- final int spotInCycle = (int) (SystemClock.elapsedRealtime() - mAnimatingPeriodStart)
- % oneCycle;
- final int numCircles = spotInCycle / MILLIS_PER_CIRCLE_ANIMATING;
-
- clearPatternDrawLookup();
- for (int i = 0; i < numCircles; i++) {
- final Cell cell = pattern.get(i);
- drawLookup[cell.row][cell.column] = true;
- }
-
- // figure out in progress portion of ghosting line
-
- final boolean needToUpdateInProgressPoint = numCircles > 0
- && numCircles < count;
-
- if (needToUpdateInProgressPoint) {
- final float percentageOfNextCircle = ((float) (spotInCycle % MILLIS_PER_CIRCLE_ANIMATING))
- / MILLIS_PER_CIRCLE_ANIMATING;
-
- final Cell currentCell = pattern.get(numCircles - 1);
- final float centerX = getCenterXForColumn(currentCell.column);
- final float centerY = getCenterYForRow(currentCell.row);
-
- final Cell nextCell = pattern.get(numCircles);
- final float dx = percentageOfNextCircle
- * (getCenterXForColumn(nextCell.column) - centerX);
- final float dy = percentageOfNextCircle
- * (getCenterYForRow(nextCell.row) - centerY);
- mInProgressX = centerX + dx;
- mInProgressY = centerY + dy;
- }
- // TODO: Infinite loop here...
- invalidate();
- }
-
- final Path currentPath = mCurrentPath;
- currentPath.rewind();
-
- // draw the circles
- for (int i = 0; i < MATRIX_WIDTH; i++) {
- float centerY = getCenterYForRow(i);
- for (int j = 0; j < MATRIX_WIDTH; j++) {
- CellState cellState = mCellStates[i][j];
- float centerX = getCenterXForColumn(j);
- float size = cellState.size * cellState.scale;
- float translationY = cellState.translateY;
- drawCircle(canvas, (int) centerX, (int) centerY + translationY,
- size, drawLookup[i][j], cellState.alpha);
- }
- }
-
- // TODO: the path should be created and cached every time we hit-detect
- // a cell
- // only the last segment of the path should be computed here
- // draw the path of the pattern (unless we are in stealth mode)
- final boolean drawPath = !mInStealthMode;
-
- if (drawPath) {
- mPathPaint.setColor(getCurrentColor(true /* partOfPattern */));
-
- boolean anyCircles = false;
- float lastX = 0f;
- float lastY = 0f;
- for (int i = 0; i < count; i++) {
- Cell cell = pattern.get(i);
-
- // only draw the part of the pattern stored in
- // the lookup table (this is only different in the case
- // of animation).
- if (!drawLookup[cell.row][cell.column]) {
- break;
- }
- anyCircles = true;
-
- float centerX = getCenterXForColumn(cell.column);
- float centerY = getCenterYForRow(cell.row);
- if (i != 0) {
- CellState state = mCellStates[cell.row][cell.column];
- currentPath.rewind();
- currentPath.moveTo(lastX, lastY);
- if (state.lineEndX != Float.MIN_VALUE
- && state.lineEndY != Float.MIN_VALUE) {
- currentPath.lineTo(state.lineEndX, state.lineEndY);
- } else {
- currentPath.lineTo(centerX, centerY);
- }
- canvas.drawPath(currentPath, mPathPaint);
- }
- lastX = centerX;
- lastY = centerY;
- }
-
- // draw last in progress section
- if ((mPatternInProgress || mPatternDisplayMode == DisplayMode.Animate)
- && anyCircles) {
- currentPath.rewind();
- currentPath.moveTo(lastX, lastY);
- currentPath.lineTo(mInProgressX, mInProgressY);
-
- mPathPaint.setAlpha((int) (calculateLastSegmentAlpha(
- mInProgressX, mInProgressY, lastX, lastY) * 255f));
- canvas.drawPath(currentPath, mPathPaint);
- }
- }
- }
-
- private float calculateLastSegmentAlpha(float x, float y, float lastX,
- float lastY) {
- float diffX = x - lastX;
- float diffY = y - lastY;
- float dist = (float) Math.sqrt(diffX * diffX + diffY * diffY);
- float frac = dist / mSquareWidth;
- return Math.min(1f, Math.max(0f, (frac - 0.3f) * 4f));
- }
-
- private int getCurrentColor(boolean partOfPattern) {
- if (!partOfPattern || mInStealthMode || mPatternInProgress) {
- // unselected circle
- return mRegularColor;
- } else if (mPatternDisplayMode == DisplayMode.Wrong) {
- // the pattern is wrong
- return mErrorColor;
- } else if (mPatternDisplayMode == DisplayMode.Correct
- || mPatternDisplayMode == DisplayMode.Animate) {
- return mSuccessColor;
- } else {
- throw new IllegalStateException("unknown display mode "
- + mPatternDisplayMode);
- }
- }
-
- /**
- * @param partOfPattern
- * Whether this circle is part of the pattern.
- */
- private void drawCircle(Canvas canvas, float centerX, float centerY,
- float size, boolean partOfPattern, float alpha) {
- mPaint.setColor(getCurrentColor(partOfPattern));
- mPaint.setAlpha((int) (alpha * 255));
- canvas.drawCircle(centerX, centerY, size / 2, mPaint);
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
- return new SavedState(superState,
- LockPatternUtils.patternToString(mPattern),
- mPatternDisplayMode.ordinal(), mInputEnabled, mInStealthMode,
- mEnableHapticFeedback);
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- final SavedState ss = (SavedState) state;
- super.onRestoreInstanceState(ss.getSuperState());
- setPattern(DisplayMode.Correct,
- LockPatternUtils.stringToPattern(ss.getSerializedPattern()));
- mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()];
- mInputEnabled = ss.isInputEnabled();
- mInStealthMode = ss.isInStealthMode();
- mEnableHapticFeedback = ss.isTactileFeedbackEnabled();
- }
-
- /**
- * The parecelable for saving and restoring a lock pattern view.
- */
- private static class SavedState extends BaseSavedState {
-
- private final String mSerializedPattern;
- private final int mDisplayMode;
- private final boolean mInputEnabled;
- private final boolean mInStealthMode;
- private final boolean mTactileFeedbackEnabled;
-
- /**
- * Constructor called from {@link LockPatternView#onSaveInstanceState()}
- */
- private SavedState(Parcelable superState, String serializedPattern,
- int displayMode, boolean inputEnabled, boolean inStealthMode,
- boolean tactileFeedbackEnabled) {
- super(superState);
- mSerializedPattern = serializedPattern;
- mDisplayMode = displayMode;
- mInputEnabled = inputEnabled;
- mInStealthMode = inStealthMode;
- mTactileFeedbackEnabled = tactileFeedbackEnabled;
- }
-
- /**
- * Constructor called from {@link #CREATOR}
- */
- private SavedState(Parcel in) {
- super(in);
- mSerializedPattern = in.readString();
- mDisplayMode = in.readInt();
- mInputEnabled = (Boolean) in.readValue(null);
- mInStealthMode = (Boolean) in.readValue(null);
- mTactileFeedbackEnabled = (Boolean) in.readValue(null);
- }
-
- public String getSerializedPattern() {
- return mSerializedPattern;
- }
-
- public int getDisplayMode() {
- return mDisplayMode;
- }
-
- public boolean isInputEnabled() {
- return mInputEnabled;
- }
-
- public boolean isInStealthMode() {
- return mInStealthMode;
- }
-
- public boolean isTactileFeedbackEnabled() {
- return mTactileFeedbackEnabled;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeString(mSerializedPattern);
- dest.writeInt(mDisplayMode);
- dest.writeValue(mInputEnabled);
- dest.writeValue(mInStealthMode);
- dest.writeValue(mTactileFeedbackEnabled);
- }
-
- @SuppressWarnings("unused")
- public static final Parcelable.Creator CREATOR = new Creator() {
-
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-
-}
diff --git a/resources/gadgets/main_header.xml b/resources/gadgets/main_header.xml
deleted file mode 100644
index f73ded4..0000000
--- a/resources/gadgets/main_header.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
diff --git a/resources/images/controls/alp_42447968_ic_action_lockpattern.svg b/resources/images/controls/alp_42447968_ic_action_lockpattern.svg
deleted file mode 100644
index f4a4929..0000000
--- a/resources/images/controls/alp_42447968_ic_action_lockpattern.svg
+++ /dev/null
@@ -1,1073 +0,0 @@
-
-
-
-
-
-
diff --git a/resources/images/stores/Feature.xcf b/resources/images/stores/Feature.xcf
deleted file mode 100644
index 2b68254..0000000
Binary files a/resources/images/stores/Feature.xcf and /dev/null differ
diff --git a/resources/images/stores/feature-graphic.svg b/resources/images/stores/feature-graphic.svg
deleted file mode 100644
index 61046dd..0000000
--- a/resources/images/stores/feature-graphic.svg
+++ /dev/null
@@ -1,108 +0,0 @@
-
-
-
-
diff --git a/resources/original source/LockPatternView.java b/resources/original source/LockPatternView.java
deleted file mode 100644
index 9fa6882..0000000
--- a/resources/original source/LockPatternView.java
+++ /dev/null
@@ -1,1133 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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.android.internal.widget;
-
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.os.Debug;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.view.HapticFeedbackConstants;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Displays and detects the user's unlock attempt, which is a drag of a finger
- * across 9 regions of the screen.
- *
- * Is also capable of displaying a static pattern in "in progress", "wrong" or
- * "correct" states.
- */
-public class LockPatternView extends View {
- // Aspect to use when rendering this view
- private static final int ASPECT_SQUARE = 0; // View will be the minimum of width/height
- private static final int ASPECT_LOCK_WIDTH = 1; // Fixed width; height will be minimum of (w,h)
- private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h)
-
- private static final boolean PROFILE_DRAWING = false;
- private final CellState[][] mCellStates;
-
- private final int mDotSize;
- private final int mDotSizeActivated;
- private final int mPathWidth;
-
- private boolean mDrawingProfilingStarted = false;
-
- private Paint mPaint = new Paint();
- private Paint mPathPaint = new Paint();
-
- /**
- * How many milliseconds we spend animating each circle of a lock pattern
- * if the animating mode is set. The entire animation should take this
- * constant * the length of the pattern to complete.
- */
- private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
-
- /**
- * This can be used to avoid updating the display for very small motions or noisy panels.
- * It didn't seem to have much impact on the devices tested, so currently set to 0.
- */
- private static final float DRAG_THRESHHOLD = 0.0f;
-
- private OnPatternListener mOnPatternListener;
- private ArrayList mPattern = new ArrayList(9);
-
- /**
- * Lookup table for the circles of the pattern we are currently drawing.
- * This will be the cells of the complete pattern unless we are animating,
- * in which case we use this to hold the cells we are drawing for the in
- * progress animation.
- */
- private boolean[][] mPatternDrawLookup = new boolean[3][3];
-
- /**
- * the in progress point:
- * - during interaction: where the user's finger is
- * - during animation: the current tip of the animating line
- */
- private float mInProgressX = -1;
- private float mInProgressY = -1;
-
- private long mAnimatingPeriodStart;
-
- private DisplayMode mPatternDisplayMode = DisplayMode.Correct;
- private boolean mInputEnabled = true;
- private boolean mInStealthMode = false;
- private boolean mEnableHapticFeedback = true;
- private boolean mPatternInProgress = false;
-
- private float mHitFactor = 0.6f;
-
- private float mSquareWidth;
- private float mSquareHeight;
-
- private final Path mCurrentPath = new Path();
- private final Rect mInvalidate = new Rect();
- private final Rect mTmpInvalidateRect = new Rect();
-
- private int mAspect;
- private int mRegularColor;
- private int mErrorColor;
- private int mSuccessColor;
-
- private Interpolator mFastOutSlowInInterpolator;
- private Interpolator mLinearOutSlowInInterpolator;
-
- /**
- * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
- */
- public static class Cell {
- int row;
- int column;
-
- // keep # objects limited to 9
- static Cell[][] sCells = new Cell[3][3];
- static {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- sCells[i][j] = new Cell(i, j);
- }
- }
- }
-
- /**
- * @param row The row of the cell.
- * @param column The column of the cell.
- */
- private Cell(int row, int column) {
- checkRange(row, column);
- this.row = row;
- this.column = column;
- }
-
- public int getRow() {
- return row;
- }
-
- public int getColumn() {
- return column;
- }
-
- /**
- * @param row The row of the cell.
- * @param column The column of the cell.
- */
- public static synchronized Cell of(int row, int column) {
- checkRange(row, column);
- return sCells[row][column];
- }
-
- private static void checkRange(int row, int column) {
- if (row < 0 || row > 2) {
- throw new IllegalArgumentException("row must be in range 0-2");
- }
- if (column < 0 || column > 2) {
- throw new IllegalArgumentException("column must be in range 0-2");
- }
- }
-
- public String toString() {
- return "(row=" + row + ",clmn=" + column + ")";
- }
- }
-
- public static class CellState {
- public float scale = 1.0f;
- public float translateY = 0.0f;
- public float alpha = 1.0f;
- public float size;
- public float lineEndX = Float.MIN_VALUE;
- public float lineEndY = Float.MIN_VALUE;
- public ValueAnimator lineAnimator;
- }
-
- /**
- * How to display the current pattern.
- */
- public enum DisplayMode {
-
- /**
- * The pattern drawn is correct (i.e draw it in a friendly color)
- */
- Correct,
-
- /**
- * Animate the pattern (for demo, and help).
- */
- Animate,
-
- /**
- * The pattern is wrong (i.e draw a foreboding color)
- */
- Wrong
- }
-
- /**
- * The call back interface for detecting patterns entered by the user.
- */
- public static interface OnPatternListener {
-
- /**
- * A new pattern has begun.
- */
- void onPatternStart();
-
- /**
- * The pattern was cleared.
- */
- void onPatternCleared();
-
- /**
- * The user extended the pattern currently being drawn by one cell.
- * @param pattern The pattern with newly added cell.
- */
- void onPatternCellAdded(List pattern);
-
- /**
- * A pattern was detected from the user.
- * @param pattern The pattern.
- */
- void onPatternDetected(List pattern);
- }
-
- public LockPatternView(Context context) {
- this(context, null);
- }
-
- public LockPatternView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LockPatternView);
-
- final String aspect = a.getString(R.styleable.LockPatternView_aspect);
-
- if ("square".equals(aspect)) {
- mAspect = ASPECT_SQUARE;
- } else if ("lock_width".equals(aspect)) {
- mAspect = ASPECT_LOCK_WIDTH;
- } else if ("lock_height".equals(aspect)) {
- mAspect = ASPECT_LOCK_HEIGHT;
- } else {
- mAspect = ASPECT_SQUARE;
- }
-
- setClickable(true);
-
-
- mPathPaint.setAntiAlias(true);
- mPathPaint.setDither(true);
-
- mRegularColor = getResources().getColor(R.color.lock_pattern_view_regular_color);
- mErrorColor = getResources().getColor(R.color.lock_pattern_view_error_color);
- mSuccessColor = getResources().getColor(R.color.lock_pattern_view_success_color);
- mRegularColor = a.getColor(R.styleable.LockPatternView_regularColor, mRegularColor);
- mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, mErrorColor);
- mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, mSuccessColor);
-
- int pathColor = a.getColor(R.styleable.LockPatternView_pathColor, mRegularColor);
- mPathPaint.setColor(pathColor);
-
- mPathPaint.setStyle(Paint.Style.STROKE);
- mPathPaint.setStrokeJoin(Paint.Join.ROUND);
- mPathPaint.setStrokeCap(Paint.Cap.ROUND);
-
- mPathWidth = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_line_width);
- mPathPaint.setStrokeWidth(mPathWidth);
-
- mDotSize = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_size);
- mDotSizeActivated = getResources().getDimensionPixelSize(
- R.dimen.lock_pattern_dot_size_activated);
-
- mPaint.setAntiAlias(true);
- mPaint.setDither(true);
-
- mCellStates = new CellState[3][3];
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- mCellStates[i][j] = new CellState();
- mCellStates[i][j].size = mDotSize;
- }
- }
-
- mFastOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
- mLinearOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
- }
-
- public CellState[][] getCellStates() {
- return mCellStates;
- }
-
- /**
- * @return Whether the view is in stealth mode.
- */
- public boolean isInStealthMode() {
- return mInStealthMode;
- }
-
- /**
- * @return Whether the view has tactile feedback enabled.
- */
- public boolean isTactileFeedbackEnabled() {
- return mEnableHapticFeedback;
- }
-
- /**
- * Set whether the view is in stealth mode. If true, there will be no
- * visible feedback as the user enters the pattern.
- *
- * @param inStealthMode Whether in stealth mode.
- */
- public void setInStealthMode(boolean inStealthMode) {
- mInStealthMode = inStealthMode;
- }
-
- /**
- * Set whether the view will use tactile feedback. If true, there will be
- * tactile feedback as the user enters the pattern.
- *
- * @param tactileFeedbackEnabled Whether tactile feedback is enabled
- */
- public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) {
- mEnableHapticFeedback = tactileFeedbackEnabled;
- }
-
- /**
- * Set the call back for pattern detection.
- * @param onPatternListener The call back.
- */
- public void setOnPatternListener(
- OnPatternListener onPatternListener) {
- mOnPatternListener = onPatternListener;
- }
-
- /**
- * Set the pattern explicitely (rather than waiting for the user to input
- * a pattern).
- * @param displayMode How to display the pattern.
- * @param pattern The pattern.
- */
- public void setPattern(DisplayMode displayMode, List pattern) {
- mPattern.clear();
- mPattern.addAll(pattern);
- clearPatternDrawLookup();
- for (Cell cell : pattern) {
- mPatternDrawLookup[cell.getRow()][cell.getColumn()] = true;
- }
-
- setDisplayMode(displayMode);
- }
-
- /**
- * Set the display mode of the current pattern. This can be useful, for
- * instance, after detecting a pattern to tell this view whether change the
- * in progress result to correct or wrong.
- * @param displayMode The display mode.
- */
- public void setDisplayMode(DisplayMode displayMode) {
- mPatternDisplayMode = displayMode;
- if (displayMode == DisplayMode.Animate) {
- if (mPattern.size() == 0) {
- throw new IllegalStateException("you must have a pattern to "
- + "animate if you want to set the display mode to animate");
- }
- mAnimatingPeriodStart = SystemClock.elapsedRealtime();
- final Cell first = mPattern.get(0);
- mInProgressX = getCenterXForColumn(first.getColumn());
- mInProgressY = getCenterYForRow(first.getRow());
- clearPatternDrawLookup();
- }
- invalidate();
- }
-
- private void notifyCellAdded() {
- sendAccessEvent(R.string.lockscreen_access_pattern_cell_added);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternCellAdded(mPattern);
- }
- }
-
- private void notifyPatternStarted() {
- sendAccessEvent(R.string.lockscreen_access_pattern_start);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternStart();
- }
- }
-
- private void notifyPatternDetected() {
- sendAccessEvent(R.string.lockscreen_access_pattern_detected);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternDetected(mPattern);
- }
- }
-
- private void notifyPatternCleared() {
- sendAccessEvent(R.string.lockscreen_access_pattern_cleared);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternCleared();
- }
- }
-
- /**
- * Clear the pattern.
- */
- public void clearPattern() {
- resetPattern();
- }
-
- /**
- * Reset all pattern state.
- */
- private void resetPattern() {
- mPattern.clear();
- clearPatternDrawLookup();
- mPatternDisplayMode = DisplayMode.Correct;
- invalidate();
- }
-
- /**
- * Clear the pattern lookup table.
- */
- private void clearPatternDrawLookup() {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- mPatternDrawLookup[i][j] = false;
- }
- }
- }
-
- /**
- * Disable input (for instance when displaying a message that will
- * timeout so user doesn't get view into messy state).
- */
- public void disableInput() {
- mInputEnabled = false;
- }
-
- /**
- * Enable input.
- */
- public void enableInput() {
- mInputEnabled = true;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- final int width = w - mPaddingLeft - mPaddingRight;
- mSquareWidth = width / 3.0f;
-
- final int height = h - mPaddingTop - mPaddingBottom;
- mSquareHeight = height / 3.0f;
- }
-
- private int resolveMeasured(int measureSpec, int desired)
- {
- int result = 0;
- int specSize = MeasureSpec.getSize(measureSpec);
- switch (MeasureSpec.getMode(measureSpec)) {
- case MeasureSpec.UNSPECIFIED:
- result = desired;
- break;
- case MeasureSpec.AT_MOST:
- result = Math.max(specSize, desired);
- break;
- case MeasureSpec.EXACTLY:
- default:
- result = specSize;
- }
- return result;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int minimumWidth = getSuggestedMinimumWidth();
- final int minimumHeight = getSuggestedMinimumHeight();
- int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
- int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
-
- switch (mAspect) {
- case ASPECT_SQUARE:
- viewWidth = viewHeight = Math.min(viewWidth, viewHeight);
- break;
- case ASPECT_LOCK_WIDTH:
- viewHeight = Math.min(viewWidth, viewHeight);
- break;
- case ASPECT_LOCK_HEIGHT:
- viewWidth = Math.min(viewWidth, viewHeight);
- break;
- }
- // Log.v(TAG, "LockPatternView dimensions: " + viewWidth + "x" + viewHeight);
- setMeasuredDimension(viewWidth, viewHeight);
- }
-
- /**
- * Determines whether the point x, y will add a new point to the current
- * pattern (in addition to finding the cell, also makes heuristic choices
- * such as filling in gaps based on current pattern).
- * @param x The x coordinate.
- * @param y The y coordinate.
- */
- private Cell detectAndAddHit(float x, float y) {
- final Cell cell = checkForNewHit(x, y);
- if (cell != null) {
-
- // check for gaps in existing pattern
- Cell fillInGapCell = null;
- final ArrayList pattern = mPattern;
- if (!pattern.isEmpty()) {
- final Cell lastCell = pattern.get(pattern.size() - 1);
- int dRow = cell.row - lastCell.row;
- int dColumn = cell.column - lastCell.column;
-
- int fillInRow = lastCell.row;
- int fillInColumn = lastCell.column;
-
- if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) {
- fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1);
- }
-
- if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) {
- fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1);
- }
-
- fillInGapCell = Cell.of(fillInRow, fillInColumn);
- }
-
- if (fillInGapCell != null &&
- !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
- addCellToPattern(fillInGapCell);
- }
- addCellToPattern(cell);
- if (mEnableHapticFeedback) {
- performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
- | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
- }
- return cell;
- }
- return null;
- }
-
- private void addCellToPattern(Cell newCell) {
- mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true;
- mPattern.add(newCell);
- if (!mInStealthMode) {
- startCellActivatedAnimation(newCell);
- }
- notifyCellAdded();
- }
-
- private void startCellActivatedAnimation(Cell cell) {
- final CellState cellState = mCellStates[cell.row][cell.column];
- startSizeAnimation(mDotSize, mDotSizeActivated, 96, mLinearOutSlowInInterpolator,
- cellState, new Runnable() {
- @Override
- public void run() {
- startSizeAnimation(mDotSizeActivated, mDotSize, 192, mFastOutSlowInInterpolator,
- cellState, null);
- }
- });
- startLineEndAnimation(cellState, mInProgressX, mInProgressY,
- getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
- }
-
- private void startLineEndAnimation(final CellState state,
- final float startX, final float startY, final float targetX, final float targetY) {
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
- valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float t = (float) animation.getAnimatedValue();
- state.lineEndX = (1 - t) * startX + t * targetX;
- state.lineEndY = (1 - t) * startY + t * targetY;
- invalidate();
- }
- });
- valueAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- state.lineAnimator = null;
- }
- });
- valueAnimator.setInterpolator(mFastOutSlowInInterpolator);
- valueAnimator.setDuration(100);
- valueAnimator.start();
- state.lineAnimator = valueAnimator;
- }
-
- private void startSizeAnimation(float start, float end, long duration, Interpolator interpolator,
- final CellState state, final Runnable endRunnable) {
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
- valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- state.size = (float) animation.getAnimatedValue();
- invalidate();
- }
- });
- if (endRunnable != null) {
- valueAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- endRunnable.run();
- }
- });
- }
- valueAnimator.setInterpolator(interpolator);
- valueAnimator.setDuration(duration);
- valueAnimator.start();
- }
-
- // helper method to find which cell a point maps to
- private Cell checkForNewHit(float x, float y) {
-
- final int rowHit = getRowHit(y);
- if (rowHit < 0) {
- return null;
- }
- final int columnHit = getColumnHit(x);
- if (columnHit < 0) {
- return null;
- }
-
- if (mPatternDrawLookup[rowHit][columnHit]) {
- return null;
- }
- return Cell.of(rowHit, columnHit);
- }
-
- /**
- * Helper method to find the row that y falls into.
- * @param y The y coordinate
- * @return The row that y falls in, or -1 if it falls in no row.
- */
- private int getRowHit(float y) {
-
- final float squareHeight = mSquareHeight;
- float hitSize = squareHeight * mHitFactor;
-
- float offset = mPaddingTop + (squareHeight - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
-
- final float hitTop = offset + squareHeight * i;
- if (y >= hitTop && y <= hitTop + hitSize) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Helper method to find the column x fallis into.
- * @param x The x coordinate.
- * @return The column that x falls in, or -1 if it falls in no column.
- */
- private int getColumnHit(float x) {
- final float squareWidth = mSquareWidth;
- float hitSize = squareWidth * mHitFactor;
-
- float offset = mPaddingLeft + (squareWidth - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
-
- final float hitLeft = offset + squareWidth * i;
- if (x >= hitLeft && x <= hitLeft + hitSize) {
- return i;
- }
- }
- return -1;
- }
-
- @Override
- public boolean onHoverEvent(MotionEvent event) {
- if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
- final int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_HOVER_ENTER:
- event.setAction(MotionEvent.ACTION_DOWN);
- break;
- case MotionEvent.ACTION_HOVER_MOVE:
- event.setAction(MotionEvent.ACTION_MOVE);
- break;
- case MotionEvent.ACTION_HOVER_EXIT:
- event.setAction(MotionEvent.ACTION_UP);
- break;
- }
- onTouchEvent(event);
- event.setAction(action);
- }
- return super.onHoverEvent(event);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!mInputEnabled || !isEnabled()) {
- return false;
- }
-
- switch(event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- handleActionDown(event);
- return true;
- case MotionEvent.ACTION_UP:
- handleActionUp(event);
- return true;
- case MotionEvent.ACTION_MOVE:
- handleActionMove(event);
- return true;
- case MotionEvent.ACTION_CANCEL:
- if (mPatternInProgress) {
- mPatternInProgress = false;
- resetPattern();
- notifyPatternCleared();
- }
- if (PROFILE_DRAWING) {
- if (mDrawingProfilingStarted) {
- Debug.stopMethodTracing();
- mDrawingProfilingStarted = false;
- }
- }
- return true;
- }
- return false;
- }
-
- private void handleActionMove(MotionEvent event) {
- // Handle all recent motion events so we don't skip any cells even when the device
- // is busy...
- final float radius = mPathWidth;
- final int historySize = event.getHistorySize();
- mTmpInvalidateRect.setEmpty();
- boolean invalidateNow = false;
- for (int i = 0; i < historySize + 1; i++) {
- final float x = i < historySize ? event.getHistoricalX(i) : event.getX();
- final float y = i < historySize ? event.getHistoricalY(i) : event.getY();
- Cell hitCell = detectAndAddHit(x, y);
- final int patternSize = mPattern.size();
- if (hitCell != null && patternSize == 1) {
- mPatternInProgress = true;
- notifyPatternStarted();
- }
- // note current x and y for rubber banding of in progress patterns
- final float dx = Math.abs(x - mInProgressX);
- final float dy = Math.abs(y - mInProgressY);
- if (dx > DRAG_THRESHHOLD || dy > DRAG_THRESHHOLD) {
- invalidateNow = true;
- }
-
- if (mPatternInProgress && patternSize > 0) {
- final ArrayList pattern = mPattern;
- final Cell lastCell = pattern.get(patternSize - 1);
- float lastCellCenterX = getCenterXForColumn(lastCell.column);
- float lastCellCenterY = getCenterYForRow(lastCell.row);
-
- // Adjust for drawn segment from last cell to (x,y). Radius accounts for line width.
- float left = Math.min(lastCellCenterX, x) - radius;
- float right = Math.max(lastCellCenterX, x) + radius;
- float top = Math.min(lastCellCenterY, y) - radius;
- float bottom = Math.max(lastCellCenterY, y) + radius;
-
- // Invalidate between the pattern's new cell and the pattern's previous cell
- if (hitCell != null) {
- final float width = mSquareWidth * 0.5f;
- final float height = mSquareHeight * 0.5f;
- final float hitCellCenterX = getCenterXForColumn(hitCell.column);
- final float hitCellCenterY = getCenterYForRow(hitCell.row);
-
- left = Math.min(hitCellCenterX - width, left);
- right = Math.max(hitCellCenterX + width, right);
- top = Math.min(hitCellCenterY - height, top);
- bottom = Math.max(hitCellCenterY + height, bottom);
- }
-
- // Invalidate between the pattern's last cell and the previous location
- mTmpInvalidateRect.union(Math.round(left), Math.round(top),
- Math.round(right), Math.round(bottom));
- }
- }
- mInProgressX = event.getX();
- mInProgressY = event.getY();
-
- // To save updates, we only invalidate if the user moved beyond a certain amount.
- if (invalidateNow) {
- mInvalidate.union(mTmpInvalidateRect);
- invalidate(mInvalidate);
- mInvalidate.set(mTmpInvalidateRect);
- }
- }
-
- private void sendAccessEvent(int resId) {
- announceForAccessibility(mContext.getString(resId));
- }
-
- private void handleActionUp(MotionEvent event) {
- // report pattern detected
- if (!mPattern.isEmpty()) {
- mPatternInProgress = false;
- cancelLineAnimations();
- notifyPatternDetected();
- invalidate();
- }
- if (PROFILE_DRAWING) {
- if (mDrawingProfilingStarted) {
- Debug.stopMethodTracing();
- mDrawingProfilingStarted = false;
- }
- }
- }
-
- private void cancelLineAnimations() {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- CellState state = mCellStates[i][j];
- if (state.lineAnimator != null) {
- state.lineAnimator.cancel();
- state.lineEndX = Float.MIN_VALUE;
- state.lineEndY = Float.MIN_VALUE;
- }
- }
- }
- }
- private void handleActionDown(MotionEvent event) {
- resetPattern();
- final float x = event.getX();
- final float y = event.getY();
- final Cell hitCell = detectAndAddHit(x, y);
- if (hitCell != null) {
- mPatternInProgress = true;
- mPatternDisplayMode = DisplayMode.Correct;
- notifyPatternStarted();
- } else if (mPatternInProgress) {
- mPatternInProgress = false;
- notifyPatternCleared();
- }
- if (hitCell != null) {
- final float startX = getCenterXForColumn(hitCell.column);
- final float startY = getCenterYForRow(hitCell.row);
-
- final float widthOffset = mSquareWidth / 2f;
- final float heightOffset = mSquareHeight / 2f;
-
- invalidate((int) (startX - widthOffset), (int) (startY - heightOffset),
- (int) (startX + widthOffset), (int) (startY + heightOffset));
- }
- mInProgressX = x;
- mInProgressY = y;
- if (PROFILE_DRAWING) {
- if (!mDrawingProfilingStarted) {
- Debug.startMethodTracing("LockPatternDrawing");
- mDrawingProfilingStarted = true;
- }
- }
- }
-
- private float getCenterXForColumn(int column) {
- return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f;
- }
-
- private float getCenterYForRow(int row) {
- return mPaddingTop + row * mSquareHeight + mSquareHeight / 2f;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- final ArrayList pattern = mPattern;
- final int count = pattern.size();
- final boolean[][] drawLookup = mPatternDrawLookup;
-
- if (mPatternDisplayMode == DisplayMode.Animate) {
-
- // figure out which circles to draw
-
- // + 1 so we pause on complete pattern
- final int oneCycle = (count + 1) * MILLIS_PER_CIRCLE_ANIMATING;
- final int spotInCycle = (int) (SystemClock.elapsedRealtime() -
- mAnimatingPeriodStart) % oneCycle;
- final int numCircles = spotInCycle / MILLIS_PER_CIRCLE_ANIMATING;
-
- clearPatternDrawLookup();
- for (int i = 0; i < numCircles; i++) {
- final Cell cell = pattern.get(i);
- drawLookup[cell.getRow()][cell.getColumn()] = true;
- }
-
- // figure out in progress portion of ghosting line
-
- final boolean needToUpdateInProgressPoint = numCircles > 0
- && numCircles < count;
-
- if (needToUpdateInProgressPoint) {
- final float percentageOfNextCircle =
- ((float) (spotInCycle % MILLIS_PER_CIRCLE_ANIMATING)) /
- MILLIS_PER_CIRCLE_ANIMATING;
-
- final Cell currentCell = pattern.get(numCircles - 1);
- final float centerX = getCenterXForColumn(currentCell.column);
- final float centerY = getCenterYForRow(currentCell.row);
-
- final Cell nextCell = pattern.get(numCircles);
- final float dx = percentageOfNextCircle *
- (getCenterXForColumn(nextCell.column) - centerX);
- final float dy = percentageOfNextCircle *
- (getCenterYForRow(nextCell.row) - centerY);
- mInProgressX = centerX + dx;
- mInProgressY = centerY + dy;
- }
- // TODO: Infinite loop here...
- invalidate();
- }
-
- final Path currentPath = mCurrentPath;
- currentPath.rewind();
-
- // draw the circles
- for (int i = 0; i < 3; i++) {
- float centerY = getCenterYForRow(i);
- for (int j = 0; j < 3; j++) {
- CellState cellState = mCellStates[i][j];
- float centerX = getCenterXForColumn(j);
- float size = cellState.size * cellState.scale;
- float translationY = cellState.translateY;
- drawCircle(canvas, (int) centerX, (int) centerY + translationY,
- size, drawLookup[i][j], cellState.alpha);
- }
- }
-
- // TODO: the path should be created and cached every time we hit-detect a cell
- // only the last segment of the path should be computed here
- // draw the path of the pattern (unless we are in stealth mode)
- final boolean drawPath = !mInStealthMode;
-
- if (drawPath) {
- mPathPaint.setColor(getCurrentColor(true /* partOfPattern */));
-
- boolean anyCircles = false;
- float lastX = 0f;
- float lastY = 0f;
- for (int i = 0; i < count; i++) {
- Cell cell = pattern.get(i);
-
- // only draw the part of the pattern stored in
- // the lookup table (this is only different in the case
- // of animation).
- if (!drawLookup[cell.row][cell.column]) {
- break;
- }
- anyCircles = true;
-
- float centerX = getCenterXForColumn(cell.column);
- float centerY = getCenterYForRow(cell.row);
- if (i != 0) {
- CellState state = mCellStates[cell.row][cell.column];
- currentPath.rewind();
- currentPath.moveTo(lastX, lastY);
- if (state.lineEndX != Float.MIN_VALUE && state.lineEndY != Float.MIN_VALUE) {
- currentPath.lineTo(state.lineEndX, state.lineEndY);
- } else {
- currentPath.lineTo(centerX, centerY);
- }
- canvas.drawPath(currentPath, mPathPaint);
- }
- lastX = centerX;
- lastY = centerY;
- }
-
- // draw last in progress section
- if ((mPatternInProgress || mPatternDisplayMode == DisplayMode.Animate)
- && anyCircles) {
- currentPath.rewind();
- currentPath.moveTo(lastX, lastY);
- currentPath.lineTo(mInProgressX, mInProgressY);
-
- mPathPaint.setAlpha((int) (calculateLastSegmentAlpha(
- mInProgressX, mInProgressY, lastX, lastY) * 255f));
- canvas.drawPath(currentPath, mPathPaint);
- }
- }
- }
-
- private float calculateLastSegmentAlpha(float x, float y, float lastX, float lastY) {
- float diffX = x - lastX;
- float diffY = y - lastY;
- float dist = (float) Math.sqrt(diffX*diffX + diffY*diffY);
- float frac = dist/mSquareWidth;
- return Math.min(1f, Math.max(0f, (frac - 0.3f) * 4f));
- }
-
- private int getCurrentColor(boolean partOfPattern) {
- if (!partOfPattern || mInStealthMode || mPatternInProgress) {
- // unselected circle
- return mRegularColor;
- } else if (mPatternDisplayMode == DisplayMode.Wrong) {
- // the pattern is wrong
- return mErrorColor;
- } else if (mPatternDisplayMode == DisplayMode.Correct ||
- mPatternDisplayMode == DisplayMode.Animate) {
- return mSuccessColor;
- } else {
- throw new IllegalStateException("unknown display mode " + mPatternDisplayMode);
- }
- }
-
- /**
- * @param partOfPattern Whether this circle is part of the pattern.
- */
- private void drawCircle(Canvas canvas, float centerX, float centerY, float size,
- boolean partOfPattern, float alpha) {
- mPaint.setColor(getCurrentColor(partOfPattern));
- mPaint.setAlpha((int) (alpha * 255));
- canvas.drawCircle(centerX, centerY, size/2, mPaint);
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
- return new SavedState(superState,
- LockPatternUtils.patternToString(mPattern),
- mPatternDisplayMode.ordinal(),
- mInputEnabled, mInStealthMode, mEnableHapticFeedback);
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- final SavedState ss = (SavedState) state;
- super.onRestoreInstanceState(ss.getSuperState());
- setPattern(
- DisplayMode.Correct,
- LockPatternUtils.stringToPattern(ss.getSerializedPattern()));
- mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()];
- mInputEnabled = ss.isInputEnabled();
- mInStealthMode = ss.isInStealthMode();
- mEnableHapticFeedback = ss.isTactileFeedbackEnabled();
- }
-
- /**
- * The parecelable for saving and restoring a lock pattern view.
- */
- private static class SavedState extends BaseSavedState {
-
- private final String mSerializedPattern;
- private final int mDisplayMode;
- private final boolean mInputEnabled;
- private final boolean mInStealthMode;
- private final boolean mTactileFeedbackEnabled;
-
- /**
- * Constructor called from {@link LockPatternView#onSaveInstanceState()}
- */
- private SavedState(Parcelable superState, String serializedPattern, int displayMode,
- boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) {
- super(superState);
- mSerializedPattern = serializedPattern;
- mDisplayMode = displayMode;
- mInputEnabled = inputEnabled;
- mInStealthMode = inStealthMode;
- mTactileFeedbackEnabled = tactileFeedbackEnabled;
- }
-
- /**
- * Constructor called from {@link #CREATOR}
- */
- private SavedState(Parcel in) {
- super(in);
- mSerializedPattern = in.readString();
- mDisplayMode = in.readInt();
- mInputEnabled = (Boolean) in.readValue(null);
- mInStealthMode = (Boolean) in.readValue(null);
- mTactileFeedbackEnabled = (Boolean) in.readValue(null);
- }
-
- public String getSerializedPattern() {
- return mSerializedPattern;
- }
-
- public int getDisplayMode() {
- return mDisplayMode;
- }
-
- public boolean isInputEnabled() {
- return mInputEnabled;
- }
-
- public boolean isInStealthMode() {
- return mInStealthMode;
- }
-
- public boolean isTactileFeedbackEnabled(){
- return mTactileFeedbackEnabled;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeString(mSerializedPattern);
- dest.writeInt(mDisplayMode);
- dest.writeValue(mInputEnabled);
- dest.writeValue(mInStealthMode);
- dest.writeValue(mTactileFeedbackEnabled);
- }
-
- public static final Parcelable.Creator CREATOR =
- new Creator() {
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-}
diff --git a/sidebar.md b/sidebar.md
new file mode 100644
index 0000000..e69de29
diff --git a/source-android-studio/.gitignore b/source-android-studio/.gitignore
deleted file mode 100644
index afbdab3..0000000
--- a/source-android-studio/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-.gradle
-/local.properties
-/.idea/workspace.xml
-/.idea/libraries
-.DS_Store
-/build
diff --git a/source-android-studio/app/.gitignore b/source-android-studio/app/.gitignore
deleted file mode 100644
index 796b96d..0000000
--- a/source-android-studio/app/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/source-android-studio/app/app.iml b/source-android-studio/app/app.iml
deleted file mode 100644
index a9eaf3a..0000000
--- a/source-android-studio/app/app.iml
+++ /dev/null
@@ -1,89 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/source-android-studio/app/build.gradle b/source-android-studio/app/build.gradle
deleted file mode 100644
index 83fe8f2..0000000
--- a/source-android-studio/app/build.gradle
+++ /dev/null
@@ -1,23 +0,0 @@
-apply plugin: 'com.android.library'
-
-android {
- compileSdkVersion 21
- buildToolsVersion "21.1.1"
-
- defaultConfig {
- minSdkVersion 7
- targetSdkVersion 21
- versionCode 45
- versionName "3.2"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
-}
-
-dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
-}
diff --git a/source-android-studio/app/proguard-rules.pro b/source-android-studio/app/proguard-rules.pro
deleted file mode 100644
index b975eaa..0000000
--- a/source-android-studio/app/proguard-rules.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in /run/media/hb/data/coding/android-sdk-linux/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/source-android-studio/app/src/main/AndroidManifest.xml b/source-android-studio/app/src/main/AndroidManifest.xml
deleted file mode 100644
index c373c29..0000000
--- a/source-android-studio/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/LockPatternActivity.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/LockPatternActivity.java
deleted file mode 100644
index f581a9c..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/LockPatternActivity.java
+++ /dev/null
@@ -1,1205 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern;
-
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-import static com.haibison.android.lockpattern.BuildConfig.DEBUG;
-import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_CAPTCHA_WIRED_DOTS;
-import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_MAX_RETRIES;
-import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_MIN_WIRED_DOTS;
-import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_STEALTH_MODE;
-import static com.haibison.android.lockpattern.util.Settings.Security.METADATA_AUTO_SAVE_PATTERN;
-import static com.haibison.android.lockpattern.util.Settings.Security.METADATA_ENCRYPTER_CLASS;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Configuration;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.Button;
-import android.widget.TextView;
-
-import com.haibison.android.lockpattern.util.IEncrypter;
-import com.haibison.android.lockpattern.util.InvalidEncrypterException;
-import com.haibison.android.lockpattern.util.LoadingView;
-import com.haibison.android.lockpattern.util.Settings;
-import com.haibison.android.lockpattern.util.Settings.Display;
-import com.haibison.android.lockpattern.util.Settings.Security;
-import com.haibison.android.lockpattern.util.UI;
-import com.haibison.android.lockpattern.widget.LockPatternUtils;
-import com.haibison.android.lockpattern.widget.LockPatternView;
-import com.haibison.android.lockpattern.widget.LockPatternView.Cell;
-import com.haibison.android.lockpattern.widget.LockPatternView.DisplayMode;
-
-/**
- * Main activity for this library.
- *
- * You can deliver result to {@link PendingIntent}'s and/ or
- * {@link ResultReceiver} too. See {@link #EXTRA_PENDING_INTENT_OK},
- * {@link #EXTRA_PENDING_INTENT_CANCELLED} and {@link #EXTRA_RESULT_RECEIVER}
- * for more details.
- *
- *
- *
NOTES
- *
- *
- * You must use one of built-in actions when calling this activity. They start
- * with {@code ACTION_*}. Otherwise the library might behave strangely (we don't
- * cover those cases).
- *
You must use one of the themes that this library supports. They start
- * with {@code R.style.Alp_42447968_Theme_*}. The reason is the themes contain
- * resources that the library needs.
- *
With {@link #ACTION_COMPARE_PATTERN}, there are 4 possible result
- * codes: {@link Activity#RESULT_OK}, {@link Activity#RESULT_CANCELED},
- * {@link #RESULT_FAILED} and {@link #RESULT_FORGOT_PATTERN}.
- *
With {@link #ACTION_VERIFY_CAPTCHA}, there are 3 possible result
- * codes: {@link Activity#RESULT_OK}, {@link Activity#RESULT_CANCELED},
- * and {@link #RESULT_FAILED}.
- *
- *
- * @author Hai Bison
- * @since v1.0
- */
-public class LockPatternActivity extends Activity {
-
- private static final String CLASSNAME = LockPatternActivity.class.getName();
-
- /**
- * Use this action to create new pattern. You can provide an
- * {@link IEncrypter} with
- * {@link Security#setEncrypterClass(android.content.Context, Class)} to
- * improve security.
- *
- * If the user created a pattern, {@link Activity#RESULT_OK} returns with
- * the pattern ({@link #EXTRA_PATTERN}). Otherwise
- * {@link Activity#RESULT_CANCELED} returns.
- *
- * @see #EXTRA_PENDING_INTENT_OK
- * @see #EXTRA_PENDING_INTENT_CANCELLED
- * @since v2.4 beta
- */
- public static final String ACTION_CREATE_PATTERN = CLASSNAME
- + ".create_pattern";
-
- /**
- * Creates new intent with {@link #ACTION_CREATE_PATTERN}. You must call
- * this intent from a UI thread.
- *
- * @param context
- * the context.
- * @return new intent.
- */
- public static Intent newIntentToCreatePattern(Context context) {
- Intent result = new Intent(ACTION_CREATE_PATTERN, null, context,
- LockPatternActivity.class);
- return result;
- }// newIntentToCreatePattern()
-
- /**
- * This method is a shortcut to call
- * {@link #newIntentToCreatePattern(Context)} from a UI thread.
- *
- * @param caller
- * must be an instance of {@link Activity}, or {@link Fragment}
- * or support library's {@code Fragment}. Other values will be
- * ignored.
- * @param context
- * the context.
- * @param requestCode
- * request code for
- * {@link Activity#startActivityForResult(Intent, int)} or
- * counterpart methods of fragments.
- * @return {@code true} if the call has been made successfully,
- * {@code false} if any exception occurred.
- * @throws NullPointerException
- * if caller or context is {@code null}.
- */
- public static boolean startToCreatePattern(Object caller, Context context,
- int requestCode) {
- return callStartActivityForResult(caller,
- newIntentToCreatePattern(context), requestCode);
- }// startToCreatePattern()
-
- /**
- * Calls {@code startActivityForResult(Intent, int)} from given caller,
- * ignores any exception.
- *
- * @param caller
- * the caller.
- * @param intent
- * the intent.
- * @param requestCode
- * request code.
- * @throws NullPointerException
- * if caller or intent is {@code null}.
- * @return {@code true} if the call has been made successfully,
- * {@code false} if any exception occurred.
- */
- public static boolean callStartActivityForResult(Object caller,
- Intent intent, int requestCode) {
- try {
- Method method = caller.getClass().getMethod(
- "startActivityForResult", Intent.class, int.class);
- method.setAccessible(true);
- method.invoke(caller, intent, requestCode);
-
- return true;
- } catch (Exception e) {
- /*
- * Just log it. We don't need to go to details here, as it's
- * responsibility of user to take care of caller.
- */
- if (DEBUG)
- Log.d(CLASSNAME, e.getMessage(), e);
- }
-
- return false;
- }// callStartActivityForResult()
-
- /**
- * Use this action to compare pattern. You provide the pattern to be
- * compared with {@link #EXTRA_PATTERN}.
- *
- * If you enabled feature auto-save pattern before (with
- * {@link Security#setAutoSavePattern(android.content.Context, boolean)} ),
- * then you don't need {@link #EXTRA_PATTERN} at this time. But if you use
- * this extra, its priority is higher than the one stored in shared
- * preferences.
- *
- * You can use {@link #EXTRA_PENDING_INTENT_FORGOT_PATTERN} to help your
- * users in case they forgot the patterns.
- *
- * If the user passes, {@link Activity#RESULT_OK} returns. If not,
- * {@link #RESULT_FAILED} returns.
- *
- * If the user cancels the task, {@link Activity#RESULT_CANCELED} returns.
- *
- * In any case, there will have extra {@link #EXTRA_RETRY_COUNT} available
- * in the intent result.
- *
- * @see #EXTRA_PATTERN
- * @see #EXTRA_PENDING_INTENT_OK
- * @see #EXTRA_PENDING_INTENT_CANCELLED
- * @see #RESULT_FAILED
- * @see #EXTRA_RETRY_COUNT
- * @since v2.4 beta
- */
- public static final String ACTION_COMPARE_PATTERN = CLASSNAME
- + ".compare_pattern";
-
- /**
- * Creates new intent with {@link #ACTION_COMPARE_PATTERN}. You must call
- * this intent from a UI thread.
- *
- * @param context
- * the context.
- * @param pattern
- * optional, see {@link #EXTRA_PATTERN}.
- * @return new intent.
- */
- public static Intent newIntentToComparePattern(Context context,
- char[] pattern) {
- Intent result = new Intent(ACTION_COMPARE_PATTERN, null, context,
- LockPatternActivity.class);
- if (pattern != null)
- result.putExtra(EXTRA_PATTERN, pattern);
-
- return result;
- }// newIntentToComparePattern()
-
- /**
- * This method is a shortcut to call
- * {@link #newIntentToComparePattern(Context, char[])} from a UI thread.
- *
- * @param caller
- * must be an instance of {@link Activity}, or {@link Fragment}
- * or support library's {@code Fragment}. Other values will be
- * ignored.
- * @param context
- * the context.
- * @param requestCode
- * request code for
- * {@link Activity#startActivityForResult(Intent, int)} or
- * counterpart methods of fragments.
- * @param pattern
- * optional, see {@link #EXTRA_PATTERN}.
- * @return {@code true} if the call has been made successfully,
- * {@code false} if any exception occurred.
- * @throws NullPointerException
- * if caller or context is {@code null}.
- */
- public static boolean startToComparePattern(Object caller, Context context,
- int requestCode, char[] pattern) {
- return callStartActivityForResult(caller,
- newIntentToComparePattern(context, pattern), requestCode);
- }// startToComparePattern()
-
- /**
- * Use this action to let the activity generate a random pattern and ask the
- * user to re-draw it to verify.
- *
- * The default length of the auto-generated pattern is {@code 4}. You can
- * change it with
- * {@link Display#setCaptchaWiredDots(android.content.Context, int)}.
- *
- * @since v2.7 beta
- */
- public static final String ACTION_VERIFY_CAPTCHA = CLASSNAME
- + ".verify_captcha";
-
- /**
- * Creates new intent with {@link #ACTION_VERIFY_CAPTCHA}. You must call
- * this intent from a UI thread.
- *
- * @param context
- * the context.
- * @return new intent.
- */
- public static Intent newIntentToVerifyCaptcha(Context context) {
- Intent result = new Intent(ACTION_VERIFY_CAPTCHA, null, context,
- LockPatternActivity.class);
- return result;
- }// newIntentToVerifyCaptcha()
-
- /**
- * This method is a shortcut to call
- * {@link #newIntentToVerifyCaptcha(Context)} from a UI thread.
- *
- * @param caller
- * must be an instance of {@link Activity}, or {@link Fragment}
- * or support library's {@code Fragment}. Other values will be
- * ignored.
- * @param context
- * the context.
- * @param requestCode
- * request code for
- * {@link Activity#startActivityForResult(Intent, int)} or
- * counterpart methods of fragments.
- * @return {@code true} if the call has been made successfully,
- * {@code false} if any exception occurred.
- * @throws NullPointerException
- * if caller or context is {@code null}.
- */
- public static boolean startToVerifyCaptcha(Object caller, Context context,
- int requestCode) {
- return callStartActivityForResult(caller,
- newIntentToVerifyCaptcha(context), requestCode);
- }// startToVerifyCaptcha()
-
- /**
- * If you use {@link #ACTION_COMPARE_PATTERN} and the user fails to "login"
- * after a number of tries, this activity will finish with this result code.
- *
- * @see #ACTION_COMPARE_PATTERN
- * @see #EXTRA_RETRY_COUNT
- */
- public static final int RESULT_FAILED = RESULT_FIRST_USER + 1;
-
- /**
- * If you use {@link #ACTION_COMPARE_PATTERN} and the user forgot his/ her
- * pattern and decided to ask for your help with recovering the pattern (
- * {@link #EXTRA_PENDING_INTENT_FORGOT_PATTERN}), this activity will finish
- * with this result code.
- *
- * @see #ACTION_COMPARE_PATTERN
- * @see #EXTRA_RETRY_COUNT
- * @see #EXTRA_PENDING_INTENT_FORGOT_PATTERN
- * @since v2.8 beta
- */
- public static final int RESULT_FORGOT_PATTERN = RESULT_FIRST_USER + 2;
-
- /**
- * For actions {@link #ACTION_COMPARE_PATTERN} and
- * {@link #ACTION_VERIFY_CAPTCHA}, this key holds the number of tries that
- * the user attempted to verify the input pattern.
- */
- public static final String EXTRA_RETRY_COUNT = CLASSNAME + ".retry_count";
-
- /**
- * Sets value of this key to a theme in {@code R.style.Alp_42447968_Theme_*}
- * . Default is the one you set in your {@code AndroidManifest.xml}. Note
- * that theme {@link R.style#Alp_42447968_Theme_Light_DarkActionBar} is
- * available in API 4+, but it only works in API 14+.
- *
- * @since v1.5.3 beta
- */
- public static final String EXTRA_THEME = CLASSNAME + ".theme";
-
- /**
- * Key to hold the pattern. It must be a {@code char[]} array.
- *
- *
- *
If you use encrypter, it should be an encrypted array.
- *
If you don't use encrypter, it should be the SHA-1 value of the
- * actual pattern. You can generate the value by
- * {@link LockPatternUtils#patternToSha1(List)}.
- *
- *
- * @since v2 beta
- */
- public static final String EXTRA_PATTERN = CLASSNAME + ".pattern";
-
- /**
- * You can provide an {@link ResultReceiver} with this key. The activity
- * will notify your receiver the same result code and intent data as you
- * will receive them in {@link #onActivityResult(int, int, Intent)}.
- *
- * @since v2.4 beta
- */
- public static final String EXTRA_RESULT_RECEIVER = CLASSNAME
- + ".result_receiver";
-
- /**
- * Put a {@link PendingIntent} into this key. It will be sent before
- * {@link Activity#RESULT_OK} will be returning. If you were calling this
- * activity with {@link #ACTION_CREATE_PATTERN}, key {@link #EXTRA_PATTERN}
- * will be attached to the original intent which the pending intent holds.
- *
- *
Notes
- *
- *
If you're going to use an activity, you don't need
- * {@link Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library
- * will call it inside {@link LockPatternActivity} .
- *
- */
- public static final String EXTRA_PENDING_INTENT_OK = CLASSNAME
- + ".pending_intent_ok";
-
- /**
- * Put a {@link PendingIntent} into this key. It will be sent before
- * {@link Activity#RESULT_CANCELED} will be returning.
- *
- *
Notes
- *
- *
If you're going to use an activity, you don't need
- * {@link Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library
- * will call it inside {@link LockPatternActivity} .
- *
- */
- public static final String EXTRA_PENDING_INTENT_CANCELLED = CLASSNAME
- + ".pending_intent_cancelled";
-
- /**
- * You put a {@link PendingIntent} into this extra. The library will show a
- * button "Forgot pattern?" and call your intent later when the user
- * taps it.
- *
- *
Notes
- *
- *
If you use an activity, you don't need
- * {@link Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library
- * will call it inside {@link LockPatternActivity} .
- *
{@link LockPatternActivity} will finish with
- * {@link #RESULT_FORGOT_PATTERN} after making a call to start
- * your pending intent.
- *
It is your responsibility to make sure the Intent is good. The
- * library doesn't cover any errors when calling your intent.
- *
- *
- * @see #ACTION_COMPARE_PATTERN
- * @since v2.8 beta
- * @author Thanks to Yan Cheng Cheok for his idea.
- */
- public static final String EXTRA_PENDING_INTENT_FORGOT_PATTERN = CLASSNAME
- + ".pending_intent_forgot_pattern";
-
- /**
- * Helper enum for button OK commands. (Because we use only one "OK" button
- * for different commands).
- *
- * @author Hai Bison
- */
- private static enum ButtonOkCommand {
- CONTINUE, FORGOT_PATTERN, DONE
- }// ButtonOkCommand
-
- /**
- * Delay time to reload the lock pattern view after a wrong pattern.
- */
- private static final long DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW = SECOND_IN_MILLIS;
-
- /*
- * FIELDS
- */
- private int mMaxRetries, mMinWiredDots, mRetryCount = 0, mCaptchaWiredDots;
- private boolean mAutoSave, mStealthMode;
- private IEncrypter mEncrypter;
- private ButtonOkCommand mBtnOkCmd;
- private Intent mIntentResult;
- private LoadingView mLoadingView;
-
- /*
- * CONTROLS
- */
- private TextView mTextInfo;
- private LockPatternView mLockPatternView;
- private View mFooter;
- private Button mBtnCancel;
- private Button mBtnConfirm;
- private View mViewGroupProgressBar;
-
- /**
- * Called when the activity is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- if (BuildConfig.DEBUG)
- Log.d(CLASSNAME, "ClassName = " + CLASSNAME);
-
- /*
- * EXTRA_THEME
- */
-
- if (getIntent().hasExtra(EXTRA_THEME))
- setTheme(getIntent().getIntExtra(EXTRA_THEME,
- R.style.Alp_42447968_Theme_Dark));
-
- super.onCreate(savedInstanceState);
-
- loadSettings();
-
- mIntentResult = new Intent();
- setResult(RESULT_CANCELED, mIntentResult);
-
- initContentView();
- }// onCreate()
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- if (BuildConfig.DEBUG)
- Log.d(CLASSNAME, "onConfigurationChanged()");
- super.onConfigurationChanged(newConfig);
- initContentView();
- }// onConfigurationChanged()
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- /*
- * Use this hook instead of onBackPressed(), because onBackPressed() is
- * not available in API 4.
- */
- if (keyCode == KeyEvent.KEYCODE_BACK
- && ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- if (mLoadingView != null)
- mLoadingView.cancel(true);
-
- finishWithNegativeResult(RESULT_CANCELED);
-
- return true;
- }// if
-
- return super.onKeyDown(keyCode, event);
- }// onKeyDown()
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- /*
- * Support canceling dialog on touching outside in APIs < 11.
- *
- * This piece of code is copied from android.view.Window. You can find
- * it by searching for methods shouldCloseOnTouch() and isOutOfBounds().
- */
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
- && event.getAction() == MotionEvent.ACTION_DOWN
- && getWindow().peekDecorView() != null) {
- final int x = (int) event.getX();
- final int y = (int) event.getY();
- final int slop = ViewConfiguration.get(this)
- .getScaledWindowTouchSlop();
- final View decorView = getWindow().getDecorView();
- boolean isOutOfBounds = (x < -slop) || (y < -slop)
- || (x > (decorView.getWidth() + slop))
- || (y > (decorView.getHeight() + slop));
- if (isOutOfBounds) {
- finishWithNegativeResult(RESULT_CANCELED);
- return true;
- }
- }// if
-
- return super.onTouchEvent(event);
- }// onTouchEvent()
-
- @Override
- protected void onDestroy() {
- if (mLoadingView != null)
- mLoadingView.cancel(true);
-
- super.onDestroy();
- }// onDestroy()
-
- /**
- * Loads settings, either from manifest or {@link Settings}.
- */
- private void loadSettings() {
- Bundle metaData = null;
- try {
- metaData = getPackageManager().getActivityInfo(getComponentName(),
- PackageManager.GET_META_DATA).metaData;
- } catch (NameNotFoundException e) {
- /*
- * Never catch this.
- */
- e.printStackTrace();
- }
-
- if (metaData != null && metaData.containsKey(METADATA_MIN_WIRED_DOTS))
- mMinWiredDots = Settings.Display.validateMinWiredDots(this,
- metaData.getInt(METADATA_MIN_WIRED_DOTS));
- else
- mMinWiredDots = Settings.Display.getMinWiredDots(this);
-
- if (metaData != null && metaData.containsKey(METADATA_MAX_RETRIES))
- mMaxRetries = Settings.Display.validateMaxRetries(this,
- metaData.getInt(METADATA_MAX_RETRIES));
- else
- mMaxRetries = Settings.Display.getMaxRetries(this);
-
- if (metaData != null
- && metaData.containsKey(METADATA_AUTO_SAVE_PATTERN))
- mAutoSave = metaData.getBoolean(METADATA_AUTO_SAVE_PATTERN);
- else
- mAutoSave = Settings.Security.isAutoSavePattern(this);
-
- if (metaData != null
- && metaData.containsKey(METADATA_CAPTCHA_WIRED_DOTS))
- mCaptchaWiredDots = Settings.Display.validateCaptchaWiredDots(this,
- metaData.getInt(METADATA_CAPTCHA_WIRED_DOTS));
- else
- mCaptchaWiredDots = Settings.Display.getCaptchaWiredDots(this);
-
- if (metaData != null && metaData.containsKey(METADATA_STEALTH_MODE))
- mStealthMode = metaData.getBoolean(METADATA_STEALTH_MODE);
- else
- mStealthMode = Settings.Display.isStealthMode(this);
-
- /*
- * Encrypter.
- */
- char[] encrypterClass;
- if (metaData != null && metaData.containsKey(METADATA_ENCRYPTER_CLASS))
- encrypterClass = metaData.getString(METADATA_ENCRYPTER_CLASS)
- .toCharArray();
- else
- encrypterClass = Settings.Security.getEncrypterClass(this);
-
- if (encrypterClass != null) {
- try {
- mEncrypter = (IEncrypter) Class.forName(
- new String(encrypterClass), false, getClassLoader())
- .newInstance();
- } catch (Throwable t) {
- throw new InvalidEncrypterException();
- }
- }
- }// loadSettings()
-
- /**
- * Initializes UI...
- */
- private void initContentView() {
- /*
- * Save all controls' state to restore later.
- */
- CharSequence infoText = mTextInfo != null ? mTextInfo.getText() : null;
- Boolean btnOkEnabled = mBtnConfirm != null ? mBtnConfirm.isEnabled()
- : null;
- LockPatternView.DisplayMode lastDisplayMode = mLockPatternView != null ? mLockPatternView
- .getDisplayMode() : null;
- List lastPattern = mLockPatternView != null ? mLockPatternView
- .getPattern() : null;
-
- setContentView(R.layout.alp_42447968_lock_pattern_activity);
- UI.adjustDialogSizeForLargeScreens(getWindow());
-
- /*
- * MAP CONTROLS
- */
-
- mTextInfo = (TextView) findViewById(R.id.alp_42447968_textview_info);
- mLockPatternView = (LockPatternView) findViewById(R.id.alp_42447968_view_lock_pattern);
-
- mFooter = findViewById(R.id.alp_42447968_viewgroup_footer);
- mBtnCancel = (Button) findViewById(R.id.alp_42447968_button_cancel);
- mBtnConfirm = (Button) findViewById(R.id.alp_42447968_button_confirm);
-
- mViewGroupProgressBar = findViewById(R.id.alp_42447968_view_group_progress_bar);
-
- /*
- * SETUP CONTROLS
- */
-
- mViewGroupProgressBar
- .setOnClickListener(mViewGroupProgressBarOnClickListener);
-
- /*
- * LOCK PATTERN VIEW
- */
-
- switch (getResources().getConfiguration().screenLayout
- & Configuration.SCREENLAYOUT_SIZE_MASK) {
- case Configuration.SCREENLAYOUT_SIZE_LARGE:
- case Configuration.SCREENLAYOUT_SIZE_XLARGE: {
- final int size = getResources().getDimensionPixelSize(
- R.dimen.alp_42447968_lockpatternview_size);
- LayoutParams lp = mLockPatternView.getLayoutParams();
- lp.width = size;
- lp.height = size;
- mLockPatternView.setLayoutParams(lp);
-
- break;
- }// LARGE / XLARGE
- }
-
- /*
- * Haptic feedback.
- */
- boolean hapticFeedbackEnabled = false;
- try {
- hapticFeedbackEnabled = android.provider.Settings.System
- .getInt(getContentResolver(),
- android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED,
- 0) != 0;
- } catch (Throwable t) {
- /*
- * Ignore it.
- */
- }
- mLockPatternView.setTactileFeedbackEnabled(hapticFeedbackEnabled);
-
- mLockPatternView.setInStealthMode(mStealthMode
- && !ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction()));
- mLockPatternView.setOnPatternListener(mLockPatternViewListener);
- if (lastPattern != null && lastDisplayMode != null
- && !ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction()))
- mLockPatternView.setPattern(lastDisplayMode, lastPattern);
-
- /*
- * COMMAND BUTTONS
- */
-
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
- mBtnCancel.setOnClickListener(mBtnCancelOnClickListener);
- mBtnConfirm.setOnClickListener(mBtnConfirmOnClickListener);
-
- mBtnCancel.setVisibility(View.VISIBLE);
- mFooter.setVisibility(View.VISIBLE);
-
- if (infoText != null)
- mTextInfo.setText(infoText);
- else
- mTextInfo
- .setText(R.string.alp_42447968_msg_draw_an_unlock_pattern);
-
- /*
- * BUTTON OK
- */
- if (mBtnOkCmd == null)
- mBtnOkCmd = ButtonOkCommand.CONTINUE;
- switch (mBtnOkCmd) {
- case CONTINUE:
- mBtnConfirm.setText(R.string.alp_42447968_cmd_continue);
- break;
- case DONE:
- mBtnConfirm.setText(R.string.alp_42447968_cmd_confirm);
- break;
- default:
- /*
- * Do nothing.
- */
- break;
- }
- if (btnOkEnabled != null)
- mBtnConfirm.setEnabled(btnOkEnabled);
- }// ACTION_CREATE_PATTERN
- else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- if (TextUtils.isEmpty(infoText))
- mTextInfo
- .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock);
- else
- mTextInfo.setText(infoText);
- if (getIntent().hasExtra(EXTRA_PENDING_INTENT_FORGOT_PATTERN)) {
- mBtnConfirm.setOnClickListener(mBtnConfirmOnClickListener);
- mBtnConfirm.setText(R.string.alp_42447968_cmd_forgot_pattern);
- mBtnConfirm.setEnabled(true);
- mFooter.setVisibility(View.VISIBLE);
- }
- }// ACTION_COMPARE_PATTERN
- else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
-
- /*
- * NOTE: EXTRA_PATTERN should hold a char[] array. In this case we
- * use it as a temporary variable to hold a list of Cell.
- */
-
- final ArrayList pattern;
- if (getIntent().hasExtra(EXTRA_PATTERN))
- pattern = getIntent()
- .getParcelableArrayListExtra(EXTRA_PATTERN);
- else
- getIntent().putParcelableArrayListExtra(
- EXTRA_PATTERN,
- pattern = LockPatternUtils
- .genCaptchaPattern(mCaptchaWiredDots));
-
- mLockPatternView.setPattern(DisplayMode.Animate, pattern);
- }// ACTION_VERIFY_CAPTCHA
- }// initContentView()
-
- /**
- * Compares {@code pattern} to the given pattern (
- * {@link #ACTION_COMPARE_PATTERN}) or to the generated "CAPTCHA" pattern (
- * {@link #ACTION_VERIFY_CAPTCHA}). Then finishes the activity if they
- * match.
- *
- * @param pattern
- * the pattern to be compared.
- */
- private void doComparePattern(final List pattern) {
- if (pattern == null)
- return;
-
- /*
- * Use a LoadingView because decrypting pattern might take time...
- */
-
- mLoadingView = new LoadingView(this,
- mViewGroupProgressBar) {
-
- @Override
- protected Object doInBackground(Void... params) {
- if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- char[] currentPattern = getIntent().getCharArrayExtra(
- EXTRA_PATTERN);
- if (currentPattern == null)
- currentPattern = Settings.Security
- .getPattern(LockPatternActivity.this);
- if (currentPattern != null) {
- if (mEncrypter != null)
- return pattern.equals(mEncrypter.decrypt(
- LockPatternActivity.this, currentPattern));
- else
- return Arrays.equals(currentPattern,
- LockPatternUtils.patternToSha1(pattern)
- .toCharArray());
- }
- }// ACTION_COMPARE_PATTERN
- else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
- return pattern.equals(getIntent()
- .getParcelableArrayListExtra(EXTRA_PATTERN));
- }// ACTION_VERIFY_CAPTCHA
-
- return false;
- }// doInBackground()
-
- @Override
- protected void onPostExecute(Object result) {
- super.onPostExecute(result);
-
- if ((Boolean) result)
- finishWithResultOk(null);
- else {
- mRetryCount++;
- mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount);
-
- if (mRetryCount >= mMaxRetries)
- finishWithNegativeResult(RESULT_FAILED);
- else {
- mLockPatternView.setDisplayMode(DisplayMode.Wrong);
- mTextInfo.setText(R.string.alp_42447968_msg_try_again);
- mLockPatternView.postDelayed(mLockPatternViewReloader,
- DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
- }
- }
- }// onPostExecute()
-
- };
-
- mLoadingView.execute();
- }// doComparePattern()
-
- /**
- * Checks and creates the pattern.
- *
- * @param pattern
- * the current pattern of lock pattern view.
- */
- private void doCheckAndCreatePattern(final List pattern) {
- if (pattern.size() < mMinWiredDots) {
- mLockPatternView.setDisplayMode(DisplayMode.Wrong);
- mTextInfo.setText(getResources().getQuantityString(
- R.plurals.alp_42447968_pmsg_connect_x_dots, mMinWiredDots,
- mMinWiredDots));
- mLockPatternView.postDelayed(mLockPatternViewReloader,
- DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
- return;
- }// if
-
- if (getIntent().hasExtra(EXTRA_PATTERN)) {
- /*
- * Use a LoadingView because decrypting pattern might take time...
- */
- mLoadingView = new LoadingView(this,
- mViewGroupProgressBar) {
-
- @Override
- protected Object doInBackground(Void... params) {
- if (mEncrypter != null)
- return pattern.equals(mEncrypter.decrypt(
- LockPatternActivity.this, getIntent()
- .getCharArrayExtra(EXTRA_PATTERN)));
- else
- return Arrays.equals(
- getIntent().getCharArrayExtra(EXTRA_PATTERN),
- LockPatternUtils.patternToSha1(pattern)
- .toCharArray());
- }// doInBackground()
-
- @Override
- protected void onPostExecute(Object result) {
- super.onPostExecute(result);
-
- if ((Boolean) result) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_your_new_unlock_pattern);
- mBtnConfirm.setEnabled(true);
- } else {
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
- mBtnConfirm.setEnabled(false);
- mLockPatternView.setDisplayMode(DisplayMode.Wrong);
- mLockPatternView.postDelayed(mLockPatternViewReloader,
- DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
- }
- }// onPostExecute()
-
- };
-
- mLoadingView.execute();
- } else {
- /*
- * Use a LoadingView because encrypting pattern might take time...
- */
- mLoadingView = new LoadingView(this,
- mViewGroupProgressBar) {
-
- @Override
- protected Object doInBackground(Void... params) {
- return mEncrypter != null ? mEncrypter.encrypt(
- LockPatternActivity.this, pattern)
- : LockPatternUtils.patternToSha1(pattern)
- .toCharArray();
- }// onCancel()
-
- @Override
- protected void onPostExecute(Object result) {
- super.onPostExecute(result);
-
- getIntent().putExtra(EXTRA_PATTERN, (char[]) result);
- mTextInfo
- .setText(R.string.alp_42447968_msg_pattern_recorded);
- mBtnConfirm.setEnabled(true);
- }// onPostExecute()
-
- };
-
- mLoadingView.execute();
- }
- }// doCheckAndCreatePattern()
-
- /**
- * Finishes activity with {@link Activity#RESULT_OK}.
- *
- * @param pattern
- * the pattern, if this is in mode creating pattern. In any
- * cases, it can be set to {@code null}.
- */
- private void finishWithResultOk(char[] pattern) {
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction()))
- mIntentResult.putExtra(EXTRA_PATTERN, pattern);
- else {
- /*
- * If the user was "logging in", minimum try count can not be zero.
- */
- mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount + 1);
- }
-
- setResult(RESULT_OK, mIntentResult);
-
- /*
- * ResultReceiver
- */
- ResultReceiver receiver = getIntent().getParcelableExtra(
- EXTRA_RESULT_RECEIVER);
- if (receiver != null) {
- Bundle bundle = new Bundle();
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction()))
- bundle.putCharArray(EXTRA_PATTERN, pattern);
- else {
- /*
- * If the user was "logging in", minimum try count can not be
- * zero.
- */
- bundle.putInt(EXTRA_RETRY_COUNT, mRetryCount + 1);
- }
- receiver.send(RESULT_OK, bundle);
- }
-
- /*
- * PendingIntent
- */
- PendingIntent pi = getIntent().getParcelableExtra(
- EXTRA_PENDING_INTENT_OK);
- if (pi != null) {
- try {
- pi.send(this, RESULT_OK, mIntentResult);
- } catch (Throwable t) {
- Log.e(CLASSNAME, "Error sending PendingIntent: " + pi, t);
- }
- }
-
- finish();
- }// finishWithResultOk()
-
- /**
- * Finishes the activity with negative result (
- * {@link Activity#RESULT_CANCELED}, {@link #RESULT_FAILED} or
- * {@link #RESULT_FORGOT_PATTERN}).
- */
- private void finishWithNegativeResult(int resultCode) {
- if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction()))
- mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount);
-
- setResult(resultCode, mIntentResult);
-
- /*
- * ResultReceiver
- */
- ResultReceiver receiver = getIntent().getParcelableExtra(
- EXTRA_RESULT_RECEIVER);
- if (receiver != null) {
- Bundle resultBundle = null;
- if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- resultBundle = new Bundle();
- resultBundle.putInt(EXTRA_RETRY_COUNT, mRetryCount);
- }
- receiver.send(resultCode, resultBundle);
- }
-
- /*
- * PendingIntent
- */
- PendingIntent pi = getIntent().getParcelableExtra(
- EXTRA_PENDING_INTENT_CANCELLED);
- if (pi != null) {
- try {
- pi.send(this, resultCode, mIntentResult);
- } catch (Throwable t) {
- Log.e(CLASSNAME, "Error sending PendingIntent: " + pi, t);
- }
- }
-
- finish();
- }// finishWithNegativeResult()
-
- /*
- * LISTENERS
- */
-
- /**
- * Pattern listener for LockPatternView.
- */
- private final LockPatternView.OnPatternListener mLockPatternViewListener = new LockPatternView.OnPatternListener() {
-
- @Override
- public void onPatternStart() {
- mLockPatternView.removeCallbacks(mLockPatternViewReloader);
- mLockPatternView.setDisplayMode(DisplayMode.Correct);
-
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_release_finger_when_done);
- mBtnConfirm.setEnabled(false);
- if (mBtnOkCmd == ButtonOkCommand.CONTINUE)
- getIntent().removeExtra(EXTRA_PATTERN);
- }// ACTION_CREATE_PATTERN
- else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock);
- }// ACTION_COMPARE_PATTERN
- else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
- }// ACTION_VERIFY_CAPTCHA
- }// onPatternStart()
-
- @Override
- public void onPatternDetected(List pattern) {
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
- doCheckAndCreatePattern(pattern);
- }// ACTION_CREATE_PATTERN
- else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- doComparePattern(pattern);
- }// ACTION_COMPARE_PATTERN
- else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
- if (!DisplayMode.Animate.equals(mLockPatternView
- .getDisplayMode()))
- doComparePattern(pattern);
- }// ACTION_VERIFY_CAPTCHA
- }// onPatternDetected()
-
- @Override
- public void onPatternCleared() {
- mLockPatternView.removeCallbacks(mLockPatternViewReloader);
-
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
- mLockPatternView.setDisplayMode(DisplayMode.Correct);
- mBtnConfirm.setEnabled(false);
- if (mBtnOkCmd == ButtonOkCommand.CONTINUE) {
- getIntent().removeExtra(EXTRA_PATTERN);
- mTextInfo
- .setText(R.string.alp_42447968_msg_draw_an_unlock_pattern);
- } else
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
- }// ACTION_CREATE_PATTERN
- else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- mLockPatternView.setDisplayMode(DisplayMode.Correct);
- mTextInfo
- .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock);
- }// ACTION_COMPARE_PATTERN
- else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
- List pattern = getIntent().getParcelableArrayListExtra(
- EXTRA_PATTERN);
- mLockPatternView.setPattern(DisplayMode.Animate, pattern);
- }// ACTION_VERIFY_CAPTCHA
- }// onPatternCleared()
-
- @Override
- public void onPatternCellAdded(List pattern) {
- // TODO Auto-generated method stub
- }// onPatternCellAdded()
-
- };// mLockPatternViewListener
-
- /**
- * Click listener for button Cancel.
- */
- private final View.OnClickListener mBtnCancelOnClickListener = new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- finishWithNegativeResult(RESULT_CANCELED);
- }// onClick()
-
- };// mBtnCancelOnClickListener
-
- /**
- * Click listener for button Confirm.
- */
- private final View.OnClickListener mBtnConfirmOnClickListener = new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
- if (mBtnOkCmd == ButtonOkCommand.CONTINUE) {
- mBtnOkCmd = ButtonOkCommand.DONE;
- mLockPatternView.clearPattern();
- mTextInfo
- .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm);
- mBtnConfirm.setText(R.string.alp_42447968_cmd_confirm);
- mBtnConfirm.setEnabled(false);
- } else {
- final char[] pattern = getIntent().getCharArrayExtra(
- EXTRA_PATTERN);
- if (mAutoSave)
- Settings.Security.setPattern(LockPatternActivity.this,
- pattern);
- finishWithResultOk(pattern);
- }
- }// ACTION_CREATE_PATTERN
- else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
- /*
- * We don't need to verify the extra. First, this button is only
- * visible if there is this extra in the intent. Second, it is
- * the responsibility of the caller to make sure the extra is
- * good.
- */
- PendingIntent pi = null;
- try {
- pi = getIntent().getParcelableExtra(
- EXTRA_PENDING_INTENT_FORGOT_PATTERN);
- pi.send();
- } catch (Throwable t) {
- Log.e(CLASSNAME, "Error sending pending intent: " + pi, t);
- }
- finishWithNegativeResult(RESULT_FORGOT_PATTERN);
- }// ACTION_COMPARE_PATTERN
- }// onClick()
-
- };// mBtnConfirmOnClickListener
-
- /**
- * This reloads the {@link #mLockPatternView} after a wrong pattern.
- */
- private final Runnable mLockPatternViewReloader = new Runnable() {
-
- @Override
- public void run() {
- mLockPatternView.clearPattern();
- mLockPatternViewListener.onPatternCleared();
- }// run()
-
- };// mLockPatternViewReloader
-
- /**
- * Click listener for view group progress bar.
- */
- private final View.OnClickListener mViewGroupProgressBarOnClickListener = new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- /*
- * Do nothing. We just don't want the user to interact with controls
- * behind this view.
- */
- }// onClick()
-
- };// mViewGroupProgressBarOnClickListener
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/collect/Lists.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/collect/Lists.java
deleted file mode 100644
index 8c55945..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/collect/Lists.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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.haibison.android.lockpattern.collect;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-/**
- * Provides static methods for creating {@code List} instances easily, and other
- * utility methods for working with lists.
- */
-public class Lists {
-
- /**
- * Creates an empty {@code ArrayList} instance.
- *
- *
- * Note: if you only need an immutable empty List, use
- * {@link Collections#emptyList} instead.
- *
- * @return a newly-created, initially-empty {@code ArrayList}
- */
- public static ArrayList newArrayList() {
- return new ArrayList();
- }
-
- /**
- * Creates a resizable {@code ArrayList} instance containing the given
- * elements.
- *
- *
- * Note: due to a bug in javac 1.5.0_06, we cannot support the
- * following:
- *
- *
- * {@code List list = Lists.newArrayList(sub1, sub2);}
- *
- *
- * where {@code sub1} and {@code sub2} are references to subtypes of
- * {@code Base}, not of {@code Base} itself. To get around this, you must
- * use:
- *
- *
- * {@code List list = Lists.newArrayList(sub1, sub2);}
- *
- * @param elements
- * the elements that the list should contain, in order
- * @return a newly-created {@code ArrayList} containing those elements
- */
- public static ArrayList newArrayList(E... elements) {
- int capacity = (elements.length * 110) / 100 + 5;
- ArrayList list = new ArrayList(capacity);
- Collections.addAll(list, elements);
- return list;
- }
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/FloatAnimator.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/FloatAnimator.java
deleted file mode 100644
index c420ba4..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/FloatAnimator.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern.util;
-
-import java.util.List;
-
-import android.os.Handler;
-
-import com.haibison.android.lockpattern.collect.Lists;
-
-/**
- * Float animator.
- *
- * @author Hai Bison
- *
- */
-public class FloatAnimator {
-
- /**
- * Event listener.
- *
- * @author Hai Bison
- *
- */
- public static interface EventListener {
-
- /**
- * Will be called when animation starts.
- *
- * @param animator
- * the animator.
- */
- void onAnimationStart(FloatAnimator animator);
-
- /**
- * Will be called when new animated value is calculated.
- *
- * @param animator
- * the animator.
- */
- void onAnimationUpdate(FloatAnimator animator);
-
- /**
- * Will be called when animation cancels.
- *
- * @param animator
- * the animator.
- */
- void onAnimationCancel(FloatAnimator animator);
-
- /**
- * Will be called when animation ends.
- *
- * @param animator
- * the animator.
- */
- void onAnimationEnd(FloatAnimator animator);
-
- }// EventListener
-
- /**
- * Simple event listener.
- *
- * @author Hai Bison
- *
- */
- public static class SimpleEventListener implements EventListener {
-
- @Override
- public void onAnimationStart(FloatAnimator animator) {
- }
-
- @Override
- public void onAnimationUpdate(FloatAnimator animator) {
- }
-
- @Override
- public void onAnimationCancel(FloatAnimator animator) {
- }
-
- @Override
- public void onAnimationEnd(FloatAnimator animator) {
- }
-
- }// SimpleEventListener
-
- /**
- * Animation delay, in milliseconds.
- */
- private static final long ANIMATION_DELAY = 1;
-
- private final float mStartValue, mEndValue;
- private final long mDuration;
- private float mAnimatedValue;
-
- private List mEventListeners;
- private Handler mHandler;
- private long mStartTime;
-
- /**
- * Creates new instance.
- *
- * @param start
- * start value.
- * @param end
- * end value.
- * @param duration
- * duration, in milliseconds. This should not be long, as delay
- * value between animation frame is just 1 millisecond.
- */
- public FloatAnimator(float start, float end, long duration) {
- mStartValue = start;
- mEndValue = end;
- mDuration = duration;
-
- mAnimatedValue = mStartValue;
- }// FloatAnimator()
-
- /**
- * Adds event listener.
- *
- * @param listener
- * the listener.
- */
- public void addEventListener(EventListener listener) {
- if (mEventListeners == null)
- mEventListeners = Lists.newArrayList();
- mEventListeners.add(listener);
- }// addEventListener()
-
- /**
- * Gets animated value.
- *
- * @return animated value.
- */
- public float getAnimatedValue() {
- return mAnimatedValue;
- }// getAnimatedValue()
-
- /**
- * Starts animating.
- */
- public void start() {
- if (mHandler != null)
- return;
-
- notifyAnimationStart();
-
- mStartTime = System.currentTimeMillis();
-
- mHandler = new Handler();
- mHandler.post(new Runnable() {
-
- @Override
- public void run() {
- final Handler handler = mHandler;
- if (handler == null)
- return;
-
- final long elapsedTime = System.currentTimeMillis()
- - mStartTime;
- if (elapsedTime > mDuration) {
- mHandler = null;
- notifyAnimationEnd();
- } else {
- float fraction = mDuration > 0 ? (float) (elapsedTime)
- / mDuration : 1f;
- float delta = mEndValue - mStartValue;
- mAnimatedValue = mStartValue + delta * fraction;
-
- notifyAnimationUpdate();
- handler.postDelayed(this, ANIMATION_DELAY);
- }
- }// run()
-
- });
- }// start()
-
- /**
- * Cancels animating.
- */
- public void cancel() {
- if (mHandler == null)
- return;
-
- mHandler.removeCallbacksAndMessages(null);
- mHandler = null;
-
- notifyAnimationCancel();
- notifyAnimationEnd();
- }// cancel()
-
- /**
- * Notifies all listeners that animation starts.
- */
- protected void notifyAnimationStart() {
- final List listeners = mEventListeners;
- if (listeners != null) {
- for (EventListener listener : listeners)
- listener.onAnimationStart(this);
- }// if
- }// notifyAnimationStart()
-
- /**
- * Notifies all listeners that animation updates.
- */
- protected void notifyAnimationUpdate() {
- final List listeners = mEventListeners;
- if (listeners != null) {
- for (EventListener listener : listeners)
- listener.onAnimationUpdate(this);
- }// if
- }// notifyAnimationUpdate()
-
- /**
- * Notifies all listeners that animation cancels.
- */
- protected void notifyAnimationCancel() {
- final List listeners = mEventListeners;
- if (listeners != null) {
- for (EventListener listener : listeners)
- listener.onAnimationCancel(this);
- }// if
- }// notifyAnimationCancel()
-
- /**
- * Notifies all listeners that animation ends.
- */
- protected void notifyAnimationEnd() {
- final List listeners = mEventListeners;
- if (listeners != null) {
- for (EventListener listener : listeners)
- listener.onAnimationEnd(this);
- }// if
- }// notifyAnimationEnd()
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/IEncrypter.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/IEncrypter.java
deleted file mode 100644
index 38de036..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/IEncrypter.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern.util;
-
-import java.util.List;
-
-import android.content.Context;
-
-import com.haibison.android.lockpattern.widget.LockPatternView.Cell;
-
-/**
- * Interface for encrypter.
- *
- * @author Hai Bison
- * @since v2 beta
- */
-public interface IEncrypter {
-
- /**
- * Encrypts {@code pattern}.
- *
- * @param context
- * the context.
- * @param pattern
- * the pattern in the form of a list of {@link Cell}.
- * @return the encrypted char array of the pattern.
- * @since v2.1 beta
- */
- char[] encrypt(Context context, List pattern);
-
- /**
- * Decrypts an encrypted pattern.
- *
- * @param context
- * the context.
- * @param encryptedPattern
- * the encrypted pattern.
- * @return the original pattern.
- */
- List decrypt(Context context, char[] encryptedPattern);
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/InvalidEncrypterException.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/InvalidEncrypterException.java
deleted file mode 100644
index 1595d51..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/InvalidEncrypterException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern.util;
-
-/**
- * Used to throw exception if given class is not implemented from
- * {@link IEncrypter}.
- *
- * @author Hai Bison
- * @since v2 beta
- */
-public class InvalidEncrypterException extends RuntimeException {
-
- /**
- * Auto-generated by Eclipse.
- */
- private static final long serialVersionUID = -1709666714042537187L;
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/LoadingDialog.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/LoadingDialog.java
deleted file mode 100644
index 6dfae12..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/LoadingDialog.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern.util;
-
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.util.Log;
-
-import com.haibison.android.lockpattern.R;
-
-/**
- * An implementation of {@link AsyncTask}, used to show {@link ProgressDialog}
- * while doing some background tasks.
- *
- * @author Hai Bison
- */
-public abstract class LoadingDialog extends
- AsyncTask {
-
- private static final String CLASSNAME = LoadingDialog.class.getName();
-
- private final ProgressDialog mDialog;
-
- /**
- * Delay time in milliseconds. Default is half a second.
- */
- private long mDelayTime = SECOND_IN_MILLIS / 2;
-
- /**
- * Flag to use along with {@link #mDelayTime}
- */
- private boolean mFinished = false;
-
- private Throwable mLastException;
-
- /**
- * Creates new instance.
- *
- * @param context
- * the context.
- * @param cancelable
- * whether the user can cancel the dialog by tapping outside of
- * it, or by pressing Back button.
- */
- public LoadingDialog(Context context, boolean cancelable) {
- this(context, cancelable, R.string.alp_42447968_loading);
- }// LoadingDialog()
-
- /**
- * Creates new instance.
- *
- * @param context
- * the context.
- * @param cancelable
- * whether the user can cancel the dialog by tapping outside of
- * it, or by pressing Back button.
- * @param msgId
- * the resource ID of the message to be displayed.
- */
- public LoadingDialog(Context context, boolean cancelable, int msgId) {
- this(context, cancelable, context.getString(msgId));
- }// LoadingDialog()
-
- /**
- * Creates new instance.
- *
- * @param context
- * the context.
- * @param cancelable
- * whether the user can cancel the dialog by tapping outside of
- * it, or by pressing Back button.
- * @param msg
- * the message to display.
- */
- public LoadingDialog(Context context, boolean cancelable, CharSequence msg) {
- mDialog = new ProgressDialog(context);
- mDialog.setCancelable(cancelable);
- mDialog.setMessage(msg);
- mDialog.setIndeterminate(true);
-
- if (cancelable) {
- mDialog.setCanceledOnTouchOutside(true);
- mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-
- @Override
- public void onCancel(DialogInterface dialog) {
- cancel(true);
- }// onCancel()
-
- });
- }
- }// LoadingDialog()
-
- /**
- * If you override this method, you must call {@code super.onPreExecute()}
- * at beginning of the method.
- */
- @Override
- protected void onPreExecute() {
- new Handler().postDelayed(new Runnable() {
-
- @Override
- public void run() {
- if (!mFinished) {
- try {
- /*
- * Sometime the activity has been finished before we
- * show this dialog, it will raise error.
- */
- mDialog.show();
- } catch (Throwable t) {
- // TODO
- Log.e(CLASSNAME, "onPreExecute() - show dialog: " + t);
- }
- }
- }
- }, getDelayTime());
- }// onPreExecute()
-
- /**
- * If you override this method, you must call
- * {@code super.onPostExecute(result)} at beginning of the method.
- */
- @Override
- protected void onPostExecute(Result result) {
- doFinish();
- }// onPostExecute()
-
- /**
- * If you override this method, you must call {@code super.onCancelled()} at
- * beginning of the method.
- */
- @Override
- protected void onCancelled() {
- doFinish();
- super.onCancelled();
- }// onCancelled()
-
- private void doFinish() {
- mFinished = true;
- try {
- /*
- * Sometime the activity has been finished before we dismiss this
- * dialog, it will raise error.
- */
- mDialog.dismiss();
- } catch (Throwable t) {
- // TODO
- Log.e(CLASSNAME, "doFinish() - dismiss dialog: " + t);
- }
- }// doFinish()
-
- /**
- * Gets the delay time before showing the dialog.
- *
- * @return the delay time
- */
- public long getDelayTime() {
- return mDelayTime;
- }// getDelayTime()
-
- /**
- * Sets the delay time before showing the dialog.
- *
- * @param delayTime
- * the delay time to set
- * @return the instance of this object, for chaining multiple calls into a
- * single statement.
- */
- public LoadingDialog setDelayTime(int delayTime) {
- mDelayTime = delayTime >= 0 ? delayTime : 0;
- return this;
- }// setDelayTime()
-
- /**
- * Sets last exception. This method is useful in case an exception raises
- * inside {@link #doInBackground(Void...)}
- *
- * @param t
- * {@link Throwable}
- */
- protected void setLastException(Throwable t) {
- mLastException = t;
- }// setLastException()
-
- /**
- * Gets last exception.
- *
- * @return {@link Throwable}
- */
- protected Throwable getLastException() {
- return mLastException;
- }// getLastException()
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/LoadingView.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/LoadingView.java
deleted file mode 100644
index 199c086..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/LoadingView.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern.util;
-
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-import android.content.Context;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.view.View;
-
-/**
- * An implementation of {@link AsyncTask}, used to show a view while doing some
- * background tasks, then hide it when done.
- *
- * @author Hai Bison
- */
-public abstract class LoadingView extends
- AsyncTask {
-
- @SuppressWarnings("unused")
- private static final String CLASSNAME = LoadingView.class.getName();
-
- private final View mView;
-
- /**
- * Delay time in milliseconds. Default delay is half a second.
- */
- private long mDelayTime = SECOND_IN_MILLIS / 2;
-
- /**
- * Flag to use along with {@link #mDelayTime}
- */
- private boolean mFinished = false;
-
- private Throwable mLastException;
-
- /**
- * Creates new instance.
- *
- * @param context
- * the context.
- * @param view
- * the view to be controlled by this async task.
- */
- public LoadingView(Context context, View view) {
- mView = view;
- }// LoadingView()
-
- /**
- * If you override this method, you must call {@code super.onPreExecute()}
- * at beginning of the method.
- */
- @Override
- protected void onPreExecute() {
- new Handler().postDelayed(new Runnable() {
-
- @Override
- public void run() {
- if (!mFinished)
- mView.setVisibility(View.VISIBLE);
- }// run()
-
- }, getDelayTime());
- }// onPreExecute()
-
- /**
- * If you override this method, you must call
- * {@code super.onPostExecute(result)} at beginning of the method.
- */
- @Override
- protected void onPostExecute(Result result) {
- doFinish();
- }// onPostExecute()
-
- /**
- * If you override this method, you must call {@code super.onCancelled()} at
- * beginning of the method.
- */
- @Override
- protected void onCancelled() {
- doFinish();
- super.onCancelled();
- }// onCancelled()
-
- private void doFinish() {
- mFinished = true;
- mView.setVisibility(View.GONE);
- }// doFinish()
-
- /**
- * Gets the delay time before showing the view.
- *
- * @return the delay time, in milliseconds.
- */
- public long getDelayTime() {
- return mDelayTime;
- }// getDelayTime()
-
- /**
- * Sets the delay time before showing the view.
- *
- * @param delayTime
- * the delay time to set, in milliseconds.
- * @return the instance of this object, for chaining multiple calls into a
- * single statement.
- */
- public LoadingView setDelayTime(int delayTime) {
- mDelayTime = delayTime >= 0 ? delayTime : 0;
- return this;
- }// setDelayTime()
-
- /**
- * Sets last exception. This method is useful in case an exception raises
- * inside {@link #doInBackground(Void...)}
- *
- * @param t
- * {@link Throwable}
- */
- protected void setLastException(Throwable t) {
- mLastException = t;
- }// setLastException()
-
- /**
- * Gets last exception.
- *
- * @return {@link Throwable}
- */
- public Throwable getLastException() {
- return mLastException;
- }// getLastException()
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/Randoms.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/Randoms.java
deleted file mode 100644
index 8a0268b..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/Randoms.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern.util;
-
-import java.util.List;
-import java.util.Random;
-
-import com.haibison.android.lockpattern.collect.Lists;
-
-/**
- * Random utilities.
- *
- * @author Hai Bison
- *
- */
-public class Randoms {
-
- private static final Random RANDOM = new Random();
-
- /**
- * This is singleton class.
- */
- private Randoms() {
- }// Random()
-
- /**
- * Generates a random integer.
- *
- * @return the random integer.
- */
- public static int randInt() {
- return RANDOM.nextInt((int) (System.nanoTime() % Integer.MAX_VALUE));
- }// randInt()
-
- /**
- * Generates a random integer within {@code [0, n)}.
- *
- * @param n
- * an arbitrary value.
- * @return the random integer.
- */
- public static int randInt(int n) {
- return n > 0 ? randInt() % n : 0;
- }// randInt()
-
- /**
- * Generates a random integer array which has length of {@code end - start},
- * and is filled by all values from {@code start} to {@code end - 1} in
- * randomized orders.
- *
- * @param start
- * the starting value.
- * @param end
- * the ending value.
- * @return the random integer array. If {@code end <= start}, an empty array
- * returns.
- */
- public static int[] randIntArray(int start, int end) {
- if (end <= start)
- return new int[0];
-
- final List values = Lists.newArrayList();
- for (int i = start; i < end; i++)
- values.add(i);
-
- final int[] result = new int[values.size()];
- for (int i = 0; i < result.length; i++) {
- int k = randInt(values.size());
- result[i] = values.get(k);
- values.remove(k);
- }// for
-
- return result;
- }// randIntArray()
-
- /**
- * Generates a random integer array which has length of {@code end}, and is
- * filled by all values from {@code 0} to {@code end - 1} in randomized
- * orders.
- *
- * @param end
- * the ending value.
- * @return the random integer array. If {@code end <= start}, an empty array
- * returns.
- */
- public static int[] randIntArray(int end) {
- return randIntArray(0, end);
- }// randIntArray()
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/ResourceUtils.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/ResourceUtils.java
deleted file mode 100644
index f818037..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/ResourceUtils.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern.util;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.TypedValue;
-
-/**
- * Resources' utilities.
- *
- * @author Hai Bison
- *
- */
-public class ResourceUtils {
-
- /**
- * This is singleton class.
- */
- private ResourceUtils() {
- }// ResourceUtils()
-
- /**
- * Convenient method for {@link Context#getTheme()} and
- * {@link Resources.Theme#resolveAttribute(int, TypedValue, boolean)}.
- *
- * @param context
- * the context.
- * @param resId
- * The resource identifier of the desired theme attribute.
- * @return the resource ID that {@link TypedValue#resourceId} points to, or
- * {@code 0} if not found.
- */
- public static int resolveAttribute(Context context, int resId) {
- return resolveAttribute(context, resId, 0);
- }// resolveAttribute()
-
- /**
- * Convenient method for {@link Context#getTheme()} and
- * {@link Resources.Theme#resolveAttribute(int, TypedValue, boolean)}.
- *
- * @param context
- * the context.
- * @param resId
- * The resource identifier of the desired theme attribute.
- * @param defaultValue
- * the default value if cannot resolve {@code resId}.
- * @return the resource ID that {@link TypedValue#resourceId} points to, or
- * {@code defaultValue} if not found.
- */
- public static int resolveAttribute(Context context, int resId,
- int defaultValue) {
- TypedValue typedValue = new TypedValue();
- if (context.getTheme().resolveAttribute(resId, typedValue, true))
- return typedValue.resourceId;
- return defaultValue;
- }// resolveAttribute()
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/Settings.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/Settings.java
deleted file mode 100644
index 9713550..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/Settings.java
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern.util;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.Build;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceManager;
-
-import com.haibison.android.lockpattern.R;
-
-/**
- * All settings for the library. They are stored in {@link SharedPreferences}.
- *
- * For some options, you can set them directly via tag {@code }
- * inside tag {@code } in AndroidManifest.xml. Refer to setter methods
- * for details. Note that the values in the manifest get higher priority than
- * the ones from this class.
- *
- * @author Hai Bison
- *
- */
-public class Settings {
-
- /**
- * This is singleton class.
- */
- private Settings() {
- }// Settings
-
- /**
- * Generates global preference filename of this library.
- *
- * @return the global preference filename.
- */
- public static final String genPreferenceFilename() {
- return String.format("%s_%s", Sys.LIB_NAME, Sys.UID);
- }// genPreferenceFilename()
-
- /**
- * Generates global database filename. the database filename.
- *
- * @return the global database filename.
- */
- public static final String genDatabaseFilename(String name) {
- return String.format("%s_%s_%s", Sys.LIB_NAME, Sys.UID, name);
- }// genDatabaseFilename()
-
- /**
- * Gets new {@link SharedPreferences}
- *
- * @param context
- * the context.
- * @return {@link SharedPreferences}
- */
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- public static SharedPreferences p(Context context) {
- /*
- * Always use application context.
- */
- return context.getApplicationContext().getSharedPreferences(
- genPreferenceFilename(), Context.MODE_MULTI_PROCESS);
- }// p()
-
- /**
- * Setup {@code pm} to use global unique filename and global access mode.
- * You must use this method if you let the user change preferences via UI
- * (such as {@link PreferenceActivity}, {@link PreferenceFragment}...).
- *
- * @param context
- * the context.
- * @param pm
- * {@link PreferenceManager}.
- * @since v2.6 beta
- */
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- public static void setupPreferenceManager(Context context,
- PreferenceManager pm) {
- pm.setSharedPreferencesMode(Context.MODE_MULTI_PROCESS);
- pm.setSharedPreferencesName(genPreferenceFilename());
- }// setupPreferenceManager()
-
- /**
- * Display preferences.
- *
- * @author Hai Bison
- *
- */
- public static class Display {
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setStealthMode(Context, boolean)
- */
- public static final String METADATA_STEALTH_MODE = "stealthMode";
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setMinWiredDots(Context, int)
- */
- public static final String METADATA_MIN_WIRED_DOTS = "minWiredDots";
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setMaxRetries(Context, int)
- */
- public static final String METADATA_MAX_RETRIES = "maxRetries";
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setCaptchaWiredDots(Context, int)
- */
- public static final String METADATA_CAPTCHA_WIRED_DOTS = "captchaWiredDots";
-
- /**
- * This is singleton class.
- */
- private Display() {
- }// Display
-
- /**
- * Checks if the library is using stealth mode or not.
- *
- * @param context
- * the context.
- * @return {@code true} or {@code false}. Default is {@code false}.
- */
- public static boolean isStealthMode(Context context) {
- return p(context)
- .getBoolean(
- context.getString(R.string.alp_42447968_pkey_display_stealth_mode),
- context.getResources()
- .getBoolean(
- R.bool.alp_42447968_pkey_display_stealth_mode_default));
- }// isStealthMode()
-
- /**
- * Sets stealth mode.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_STEALTH_MODE}.
- *
- * @param context
- * the context.
- * @param v
- * the value.
- */
- public static void setStealthMode(Context context, boolean v) {
- p(context)
- .edit()
- .putBoolean(
- context.getString(R.string.alp_42447968_pkey_display_stealth_mode),
- v).commit();
- }// setStealthMode()
-
- /**
- * Gets minimum wired dots allowed for a pattern.
- *
- * @param context
- * the context.
- * @return the minimum wired dots allowed for a pattern. Default is
- * {@code 4}.
- */
- public static int getMinWiredDots(Context context) {
- return p(context)
- .getInt(context
- .getString(R.string.alp_42447968_pkey_display_min_wired_dots),
- context.getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_min_wired_dots_default));
- }// getMinWiredDots()
-
- /**
- * Validates min wired dots.
- *
- * @param context
- * the context.
- * @param v
- * the input value.
- * @return the correct value.
- */
- public static int validateMinWiredDots(Context context, int v) {
- if (v <= 0 || v > 9)
- v = context
- .getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_min_wired_dots_default);
- return v;
- }// validateMinWiredDots()
-
- /**
- * Sets minimum wired dots allowed for a pattern.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_MIN_WIRED_DOTS}.
- *
- * @param context
- * the context.
- * @param v
- * the minimum wired dots allowed for a pattern.
- */
- public static void setMinWiredDots(Context context, int v) {
- v = validateMinWiredDots(context, v);
- p(context)
- .edit()
- .putInt(context
- .getString(R.string.alp_42447968_pkey_display_min_wired_dots),
- v).commit();
- }// setMinWiredDots()
-
- /**
- * Gets max retries allowed in mode comparing pattern.
- *
- * @param context
- * the context.
- * @return the max retries allowed in mode comparing pattern. Default is
- * {@code 5}.
- */
- public static int getMaxRetries(Context context) {
- return p(context)
- .getInt(context
- .getString(R.string.alp_42447968_pkey_display_max_retries),
- context.getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_max_retries_default));
- }// getMaxRetries()
-
- /**
- * Validates max retries.
- *
- * @param context
- * the context.
- * @param v
- * the input value.
- * @return the correct value.
- */
- public static int validateMaxRetries(Context context, int v) {
- if (v <= 0)
- v = context
- .getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_max_retries_default);
- return v;
- }// validateMaxRetries()
-
- /**
- * Sets max retries allowed in mode comparing pattern.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_MAX_RETRIES}.
- *
- * @param context
- * the context.
- * @param v
- * the max retries allowed in mode comparing pattern.
- */
- public static void setMaxRetries(Context context, int v) {
- v = validateMaxRetries(context, v);
- p(context)
- .edit()
- .putInt(context
- .getString(R.string.alp_42447968_pkey_display_max_retries),
- v).commit();
- }// setMaxRetries()
-
- /**
- * Gets wired dots for a "CAPTCHA" pattern.
- *
- * @param context
- * the context.
- * @return the wired dots for a "CAPTCHA" pattern. Default is {@code 4}.
- */
- public static int getCaptchaWiredDots(Context context) {
- return p(context)
- .getInt(context
- .getString(R.string.alp_42447968_pkey_display_captcha_wired_dots),
- context.getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_captcha_wired_dots_default));
- }// getCaptchaWiredDots()
-
- /**
- * Validates CAPTCHA wired dots.
- *
- * @param context
- * the context.
- * @param v
- * the input value.
- * @return the correct value.
- */
- public static int validateCaptchaWiredDots(Context context, int v) {
- if (v <= 0 || v > 9)
- v = context
- .getResources()
- .getInteger(
- R.integer.alp_42447968_pkey_display_captcha_wired_dots_default);
- return v;
- }// validateCaptchaWiredDots()
-
- /**
- * Sets wired dots for a "CAPTCHA" pattern.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_CAPTCHA_WIRED_DOTS}.
- *
- * @param context
- * the context.
- * @param v
- * the wired dots for a "CAPTCHA" pattern.
- */
- public static void setCaptchaWiredDots(Context context, int v) {
- v = validateCaptchaWiredDots(context, v);
- p(context)
- .edit()
- .putInt(context
- .getString(R.string.alp_42447968_pkey_display_captcha_wired_dots),
- v).commit();
- }// setCaptchaWiredDots()
-
- }// Display
-
- /**
- * Security preferences.
- *
- * @author Hai Bison
- *
- */
- public static class Security {
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setEncrypterClass(Context, char[])
- * @see #setEncrypterClass(Context, Class)
- */
- public static final String METADATA_ENCRYPTER_CLASS = "encrypterClass";
-
- /**
- * Name to use for tag {@code } in AndroidManifest.xml.
- *
- * @see #setAutoSavePattern(Context, boolean)
- */
- public static final String METADATA_AUTO_SAVE_PATTERN = "autoSavePattern";
-
- /**
- * This is singleton class.
- */
- private Security() {
- }// Security
-
- /**
- * Checks if the library is using auto-save pattern mode.
- *
- * @param context
- * the context.
- * @return {@code true} or {@code false}. Default is {@code false}.
- */
- public static boolean isAutoSavePattern(Context context) {
- return p(context)
- .getBoolean(
- context.getString(R.string.alp_42447968_pkey_sys_auto_save_pattern),
- context.getResources()
- .getBoolean(
- R.bool.alp_42447968_pkey_sys_auto_save_pattern_default));
- }// isAutoSavePattern()
-
- /**
- * Sets auto-save pattern mode.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_AUTO_SAVE_PATTERN}.
- *
- * @param context
- * the context.
- * @param v
- * the auto-save mode.
- */
- public static void setAutoSavePattern(Context context, boolean v) {
- p(context)
- .edit()
- .putBoolean(
- context.getString(R.string.alp_42447968_pkey_sys_auto_save_pattern),
- v).commit();
- if (!v)
- setPattern(context, null);
- }// setAutoSavePattern()
-
- /**
- * Gets the pattern.
- *
- * @param context
- * the context.
- * @return the pattern. Default is {@code null}.
- */
- public static char[] getPattern(Context context) {
- String pattern = p(context).getString(
- context.getString(R.string.alp_42447968_pkey_sys_pattern),
- null);
- return pattern == null ? null : pattern.toCharArray();
- }// getPattern()
-
- /**
- * Sets the pattern.
- *
- * @param context
- * the context.
- * @param pattern
- * the pattern, can be {@code null} to reset it.
- */
- public static void setPattern(Context context, char[] pattern) {
- p(context)
- .edit()
- .putString(
- context.getString(R.string.alp_42447968_pkey_sys_pattern),
- pattern != null ? new String(pattern) : null)
- .commit();
- }// setPattern()
-
- /**
- * Gets encrypter class.
- *
- * @param context
- * the context.
- * @return the full name of encrypter class. Default is {@code null}.
- */
- public static char[] getEncrypterClass(Context context) {
- String clazz = p(context)
- .getString(
- context.getString(R.string.alp_42447968_pkey_sys_encrypter_class),
- null);
- return clazz == null ? null : clazz.toCharArray();
- }// getEncrypterClass()
-
- /**
- * Sets encrypter class.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_ENCRYPTER_CLASS}.
- *
- * @param context
- * the context.
- * @param clazz
- * the encrypter class, can be {@code null} if you don't want
- * to use it.
- */
- public static void setEncrypterClass(Context context, Class> clazz) {
- setEncrypterClass(context, clazz != null ? clazz.getName()
- .toCharArray() : null);
- }// setEncrypterClass()
-
- /**
- * Sets encrypter class.
- *
- * You can set this value in AndroidManifest.xml with
- * {@link #METADATA_ENCRYPTER_CLASS}.
- *
- * @param context
- * the context.
- * @param clazz
- * the full name of encrypter class, can be {@code null} if
- * you don't want to use it.
- */
- public static void setEncrypterClass(Context context, char[] clazz) {
- p(context)
- .edit()
- .putString(
- context.getString(R.string.alp_42447968_pkey_sys_encrypter_class),
- clazz != null ? new String(clazz) : null).commit();
- }// setEncrypterClass()
-
- }// Security
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/SimpleWeakEncryption.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/SimpleWeakEncryption.java
deleted file mode 100644
index 7805e05..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/SimpleWeakEncryption.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern.util;
-
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.PBEKeySpec;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * The simple-and-weak encryption utilities.
- *
- * @author Hai Bison
- *
- */
-public class SimpleWeakEncryption {
-
- private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
- private static final String SECRET_KEY_FACTORY_ALGORITHM = "PBEWithMD5AndDES";
- private static final String SECRET_KEY_SPEC_ALGORITHM = "AES";
-
- private static final int KEY_LEN = 256;
- private static final int IV_LEN = 16;
- private static final int ITERATION_COUNT = 512;
- private static final char SEPARATOR = '@';
-
- public static final String UTF8 = "UTF-8";
- public static final String SHA256 = "SHA-256";
-
- /**
- * This is singleton class.
- */
- private SimpleWeakEncryption() {
- }// SimpleWeakEncryption()
-
- /**
- * Encrypts {@code data} by {@code key}.
- *
- * @param password
- * the secret key.
- * @param salt
- * the salt, can be {@code null}. But it is highly recommended
- * that you should provide it.
- * @param data
- * the data.
- * @return the encrypted data.
- * @throws RuntimeException
- * which wraps the original exception related to cipher process.
- */
- public static String encrypt(final char[] password, byte[] salt,
- final String data) {
- byte[] bytes = null;
- try {
- bytes = data.getBytes(UTF8);
- } catch (UnsupportedEncodingException e) {
- /*
- * Never catch this.
- */
- throw new RuntimeException(e);
- }
-
- Cipher cipher = null;
-
- try {
- cipher = Cipher.getInstance(TRANSFORMATION);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- } catch (NoSuchPaddingException e) {
- throw new RuntimeException(e);
- }
-
- /*
- * cipher.getIV() doesn't work the same for different API levels. So
- * we're using this technique.
- */
- final byte[] iv = SecureRandom.getSeed(IV_LEN);
-
- try {
- cipher.init(Cipher.ENCRYPT_MODE, genKey(password, salt),
- new IvParameterSpec(iv));
- } catch (InvalidKeyException e) {
- throw new RuntimeException(e);
- } catch (InvalidAlgorithmParameterException e) {
- throw new RuntimeException(e);
- }
-
- try {
- bytes = cipher.doFinal(bytes);
- return String.format("%s%s%s", Base36.toBase36(iv), SEPARATOR,
- Base36.toBase36(bytes));
- } catch (IllegalBlockSizeException e) {
- throw new RuntimeException(e);
- } catch (BadPaddingException e) {
- throw new RuntimeException(e);
- }
- }// encrypt()
-
- /**
- * Decrypts an encrypted string ({@code data}) by {@code key}.
- *
- * @param password
- * the password.
- * @param salt
- * the salt, can be {@code null}. But it is highly recommended
- * that you should provide it.
- * @param data
- * the data.
- * @return the decrypted string, or {@code null} if {@code password} is
- * invalid.
- * @throws RuntimeException
- * which wraps the original exception related to cipher process.
- */
- public static String decrypt(final char[] password, byte[] salt,
- final String data) {
- Cipher cipher = null;
- try {
- cipher = Cipher.getInstance(TRANSFORMATION);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- } catch (NoSuchPaddingException e) {
- throw new RuntimeException(e);
- }
-
- final int iSeparator = data.indexOf(SEPARATOR);
-
- try {
- cipher.init(
- Cipher.DECRYPT_MODE,
- genKey(password, salt),
- new IvParameterSpec(Base36.toBytes(data.substring(0,
- iSeparator))));
- } catch (InvalidKeyException e) {
- throw new RuntimeException(e);
- } catch (InvalidAlgorithmParameterException e) {
- throw new RuntimeException(e);
- }
-
- try {
- return new String(cipher.doFinal(Base36.toBytes(data
- .substring(iSeparator + 1))), UTF8);
- } catch (IllegalBlockSizeException e) {
- throw new RuntimeException(e);
- } catch (BadPaddingException e) {
- throw new RuntimeException(e);
- } catch (UnsupportedEncodingException e) {
- /*
- * Never catch this.
- */
- throw new RuntimeException(e);
- }
- }// decrypt()
-
- /**
- * Generates secret key.
- *
- * @param password
- * the password.
- * @param salt
- * the salt, can be {@code null}. But it is highly recommended
- * that you should provide it.
- * @return the secret key.
- * @throws RuntimeException
- * which wraps the original exception related to cipher process.
- */
- private static Key genKey(char[] password, byte[] salt) {
- SecretKeyFactory factory;
- try {
- factory = SecretKeyFactory
- .getInstance(SECRET_KEY_FACTORY_ALGORITHM);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
-
- if (salt != null && salt.length > 0)
- salt = sha256(salt);
- else
- salt = sha256(new String(password));
-
- KeySpec spec = new PBEKeySpec(password, salt, ITERATION_COUNT, KEY_LEN);
-
- SecretKey tmp = null;
- try {
- tmp = factory.generateSecret(spec);
- } catch (InvalidKeySpecException e) {
- throw new RuntimeException(e);
- }
-
- return new SecretKeySpec(sha256(tmp.getEncoded()),
- SECRET_KEY_SPEC_ALGORITHM);
- }// genKey()
-
- /**
- * Calculates SHA-256 of a string.
- *
- * @param s
- * the string.
- * @return the SHA-256 of given string.
- * @throws RuntimeException
- * which wraps {@link UnsupportedEncodingException} in case the
- * system does not support {@link #UTF8}.
- */
- public static byte[] sha256(String s) {
- try {
- return sha256(s.getBytes(UTF8));
- } catch (UnsupportedEncodingException e) {
- /*
- * Never catch this.
- */
- throw new RuntimeException(e);
- }
- }// sha256()
-
- /**
- * Calculates SHA-256 of a byte array.
- *
- * @param bytes
- * the byte array.
- * @return the SHA-256 of given data.
- * @throws RuntimeException
- * which wraps {@link NoSuchAlgorithmException} in case the
- * system does not support calculating message digest of
- * {@link #SHA256}.
- */
- public static byte[] sha256(byte[] bytes) {
- try {
- MessageDigest md = MessageDigest.getInstance(SHA256);
- md.update(bytes);
- return md.digest();
- } catch (NoSuchAlgorithmException e) {
- /*
- * Never catch this.
- */
- throw new RuntimeException(e);
- }
- }// sha256()
-
- /**
- * Base-36 utilities.
- *
- * @author Hai Bison
- *
- */
- public static class Base36 {
-
- /**
- * This is singleton class.
- */
- private Base36() {
- }// Base36()
-
- /**
- * Converts a byte array to base-36.
- *
- * @param bytes
- * the byte array.
- * @return the base-36 string representing the data given.
- */
- public static String toBase36(byte[] bytes) {
- return new BigInteger(bytes).toString(Character.MAX_RADIX);
- }// toBase36()
-
- /**
- * Converts a base-36 string to its byte array.
- *
- * @param base36
- * the base-36 string.
- * @return the original data.
- */
- public static byte[] toBytes(String base36) {
- return new BigInteger(base36, Character.MAX_RADIX).toByteArray();
- }// toBytes()
-
- }// Base36
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/Sys.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/Sys.java
deleted file mode 100644
index 6e6ef8f..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/Sys.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern.util;
-
-/**
- * System utilities.
- *
- * @author Hai Bison
- *
- */
-public class Sys {
-
- /**
- * This is singleton class.
- */
- private Sys() {
- }// Sys
-
- /**
- * The library name.
- */
- public static final String LIB_NAME = "android-lockpattern";
-
- /**
- * The library version code.
- */
- public static final int LIB_VERSION_CODE = 45;
-
- /**
- * The library version name.
- */
- public static final String LIB_VERSION_NAME = "3.2";
-
- /**
- * The library package name.
- */
- public static final String LIB_PACKAGE_NAME = "com.haibison.android.lockpattern";
-
- /**
- * This unique ID is used for some stuffs such as preferences' file name.
- *
- * @since v2.6 beta
- */
- public static final String UID = "a6eedbe5-1cf9-4684-8134-ad4ec9f6a131";
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/UI.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/UI.java
deleted file mode 100644
index f3d7963..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/util/UI.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 2012 Hai Bison
- *
- * 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.haibison.android.lockpattern.util;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Window;
-
-import com.haibison.android.lockpattern.BuildConfig;
-
-/**
- * UI utilities.
- *
- * @author Hai Bison
- */
-public class UI {
-
- private static final String CLASSNAME = UI.class.getName();
-
- /**
- * The screen sizes.
- *
- * @author Hai Bison
- *
- */
- public static enum ScreenSize {
- /**
- * Small.
- */
- SMALL(1, 1, 1, 1),
- /**
- * Normal.
- */
- NORMAL(1, 1, 1, 1),
- /**
- * Large.
- */
- LARGE(.6f, .9f, .6f, .9f),
- /**
- * X-Large.
- */
- XLARGE(.6f, .9f, .5f, .7f),
- /**
- * Undefined.
- */
- UNDEFINED(1, 1, 1, 1);
-
- /**
- * The desired fixed width for a dialog along the minor axis (the screen
- * is in portrait). This is a fraction.
- */
- public final float fixedWidthMinor,
- /**
- * The desired fixed width for a dialog along the major axis (the screen
- * is in landscape). This is a fraction.
- */
- fixedWidthMajor,
- /**
- * The desired fixed height for a dialog along the minor axis (the
- * screen is in landscape). This is a fraction.
- */
- fixedHeightMinor,
- /**
- * The desired fixed height for a dialog along the major axis (the
- * screen is in portrait). This is a fraction.
- */
- fixedHeightMajor;
-
- /**
- * Creates new instance.
- *
- * @param fixedHeightMajor
- * the fixed height major.
- * @param fixedHeightMinor
- * the fixed height minor.
- * @param fixedWidthMajor
- * the fixed width major.
- * @param fixedWidthMinor
- * the fixed width minor.
- */
- private ScreenSize(float fixedHeightMajor, float fixedHeightMinor,
- float fixedWidthMajor, float fixedWidthMinor) {
- this.fixedHeightMajor = fixedHeightMajor;
- this.fixedHeightMinor = fixedHeightMinor;
- this.fixedWidthMajor = fixedWidthMajor;
- this.fixedWidthMinor = fixedWidthMinor;
- }// ScreenSize()
-
- /**
- * Gets current screen size.
- *
- * @param context
- * the context.
- * @return current screen size.
- */
- public static ScreenSize getCurrent(Context context) {
- switch (context.getResources().getConfiguration().screenLayout
- & Configuration.SCREENLAYOUT_SIZE_MASK) {
- case Configuration.SCREENLAYOUT_SIZE_SMALL:
- return SMALL;
- case Configuration.SCREENLAYOUT_SIZE_NORMAL:
- return NORMAL;
- case Configuration.SCREENLAYOUT_SIZE_LARGE:
- return LARGE;
- case Configuration.SCREENLAYOUT_SIZE_XLARGE:
- return XLARGE;
- default:
- return UNDEFINED;
- }
- }// getCurrent()
-
- }// ScreenSize
-
- /**
- * This is singleton class.
- */
- private UI() {
- }// UI
-
- /**
- * Uses a fixed size for {@code dialog} in large screens.
- *
- * @param dialog
- * the dialog.
- */
- public static void adjustDialogSizeForLargeScreens(Dialog dialog) {
- adjustDialogSizeForLargeScreens(dialog.getWindow());
- }// adjustDialogSizeForLargeScreens()
-
- /**
- * Uses a fixed size for {@code dialogWindow} in large screens.
- *
- * @param dialogWindow
- * the window of the dialog.
- */
- public static void adjustDialogSizeForLargeScreens(Window dialogWindow) {
- if (BuildConfig.DEBUG)
- Log.d(CLASSNAME, "adjustDialogSizeForLargeScreens()");
-
- if (!dialogWindow.isFloating())
- return;
-
- final ScreenSize screenSize = ScreenSize.getCurrent(dialogWindow
- .getContext());
- switch (screenSize) {
- case LARGE:
- case XLARGE:
- break;
- default:
- return;
- }
-
- final DisplayMetrics metrics = dialogWindow.getContext().getResources()
- .getDisplayMetrics();
- final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
-
- int width = metrics.widthPixels;// dialogWindow.getDecorView().getWidth();
- int height = metrics.heightPixels;// dialogWindow.getDecorView().getHeight();
- if (BuildConfig.DEBUG)
- Log.d(CLASSNAME,
- String.format("width = %,d | height = %,d", width, height));
-
- width = (int) (width * (isPortrait ? screenSize.fixedWidthMinor
- : screenSize.fixedWidthMajor));
- height = (int) (height * (isPortrait ? screenSize.fixedHeightMajor
- : screenSize.fixedHeightMinor));
-
- if (BuildConfig.DEBUG)
- Log.d(CLASSNAME, String.format(
- "NEW >>> width = %,d | height = %,d", width, height));
- dialogWindow.setLayout(width, height);
- }// adjustDialogSizeForLargeScreens()
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/widget/LockPatternUtils.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/widget/LockPatternUtils.java
deleted file mode 100644
index d2cb683..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/widget/LockPatternUtils.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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.haibison.android.lockpattern.widget;
-
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-import android.util.Log;
-
-import com.haibison.android.lockpattern.BuildConfig;
-import com.haibison.android.lockpattern.collect.Lists;
-import com.haibison.android.lockpattern.util.Randoms;
-
-/**
- * Utilities for the lock pattern and its settings.
- */
-public class LockPatternUtils {
-
- /**
- * Used for debugging...
- */
- private static final String CLASSNAME = LockPatternUtils.class.getName();
-
- /**
- * "UTF-8"
- */
- public static final String UTF8 = "UTF-8";
-
- /**
- * "SHA-1"
- */
- public static final String SHA1 = "SHA-1";
-
- /**
- * This is singleton class.
- */
- private LockPatternUtils() {
- }// LockPatternUtils
-
- /**
- * Deserialize a pattern.
- *
- * @param string
- * The pattern serialized with {@link #patternToString}
- * @return The pattern.
- */
- public static List stringToPattern(String string) {
- List result = Lists.newArrayList();
-
- try {
- final byte[] bytes = string.getBytes(UTF8);
- for (int i = 0; i < bytes.length; i++) {
- byte b = bytes[i];
- result.add(LockPatternView.Cell.of(b / 3, b % 3));
- }
- } catch (UnsupportedEncodingException e) {
- // never catch this
- }
-
- return result;
- }// stringToPattern()
-
- /**
- * Serialize a pattern.
- *
- * @param pattern
- * The pattern.
- * @return The pattern in string form.
- */
- public static String patternToString(List pattern) {
- if (pattern == null) {
- return "";
- }
- final int patternSize = pattern.size();
-
- byte[] res = new byte[patternSize];
- for (int i = 0; i < patternSize; i++) {
- LockPatternView.Cell cell = pattern.get(i);
- res[i] = (byte) (cell.row * 3 + cell.column);
- }
- try {
- return new String(res, UTF8);
- } catch (UnsupportedEncodingException e) {
- // never catch this
- return "";
- }
- }// patternToString()
-
- /**
- * Serializes a pattern
- *
- * @param pattern
- * The pattern
- * @return The SHA-1 string of the pattern got from
- * {@link #patternToString(List)}
- */
- public static String patternToSha1(List pattern) {
- try {
- MessageDigest md = MessageDigest.getInstance(SHA1);
- md.update(patternToString(pattern).getBytes(UTF8));
-
- byte[] digest = md.digest();
- BigInteger bi = new BigInteger(1, digest);
- return String.format((Locale) null,
- "%0" + (digest.length * 2) + "x", bi).toLowerCase();
- } catch (NoSuchAlgorithmException e) {
- // never catch this
- return "";
- } catch (UnsupportedEncodingException e) {
- // never catch this
- return "";
- }
- }// patternToSha1()
-
- /**
- * Generates a random "CAPTCHA" pattern. By saying "CAPTCHA", this method
- * ensures that the generated pattern is easy for the user to re-draw.
- *
- * Notes: This method is not optimized and not
- * benchmarked yet for large size of the pattern's matrix. Currently it
- * works fine with a matrix of {@code 3x3} cells. Be careful when the size
- * increases.
- *
- *
- * @param size
- * the size of the pattern to be generated.
- * @return the generated pattern.
- * @throws IndexOutOfBoundsException
- * if {@code size <= 0} or {@code size > }
- * {@link LockPatternView#MATRIX_SIZE}.
- * @since v2.7 beta
- * @author Hai Bison
- */
- public static ArrayList genCaptchaPattern(int size)
- throws IndexOutOfBoundsException {
- if (size <= 0 || size > LockPatternView.MATRIX_SIZE)
- throw new IndexOutOfBoundsException(
- "`size` must be in range [1, `LockPatternView.MATRIX_SIZE`]");
-
- final List usedIds = Lists.newArrayList();
- int lastId = Randoms.randInt(LockPatternView.MATRIX_SIZE);
- usedIds.add(lastId);
-
- while (usedIds.size() < size) {
- /*
- * We start from an empty matrix, so there's always a break point to
- * exit this loop.
- */
-
- if (BuildConfig.DEBUG)
- Log.d(CLASSNAME, " >> lastId = " + lastId);
-
- final int lastRow = lastId / LockPatternView.MATRIX_WIDTH;
- final int lastCol = lastId % LockPatternView.MATRIX_WIDTH;
-
- /*
- * This is the max available rows/ columns that we can reach from
- * the cell of `lastId` to the border of the matrix.
- */
- final int maxDistance = Math.max(
- Math.max(lastRow, LockPatternView.MATRIX_WIDTH - lastRow),
- Math.max(lastCol, LockPatternView.MATRIX_WIDTH - lastCol));
-
- lastId = -1;
-
- /*
- * Starting from `distance` = 1, find the closest-available
- * neighbour value of the cell [lastRow, lastCol].
- */
- for (int distance = 1; distance <= maxDistance; distance++) {
- /*
- * Now we have a square surrounding the current cell. We call it
- * ABCD, in which A is top-left, and C is bottom-right.
- */
-
- final int rowA = lastRow - distance;
- final int colA = lastCol - distance;
- final int rowC = lastRow + distance;
- final int colC = lastCol + distance;
-
- int[] randomValues;
-
- /*
- * Process randomly AB, BC, CD, and DA. Break the loop as soon
- * as we find one value.
- */
- final int[] lines = Randoms.randIntArray(4);
- for (int line : lines) {
- switch (line) {
- case 0: {
- if (rowA >= 0) {
- randomValues = Randoms.randIntArray(Math.max(0,
- colA), Math.min(
- LockPatternView.MATRIX_WIDTH, colC + 1));
- for (int c : randomValues) {
- lastId = rowA * LockPatternView.MATRIX_WIDTH
- + c;
- if (usedIds.contains(lastId))
- lastId = -1;
- else
- break;
- }
- }
- break;
- }// AB
- case 1: {
- if (colC < LockPatternView.MATRIX_WIDTH) {
- randomValues = Randoms.randIntArray(Math.max(0,
- rowA + 1), Math.min(
- LockPatternView.MATRIX_WIDTH, rowC + 1));
- for (int r : randomValues) {
- lastId = r * LockPatternView.MATRIX_WIDTH
- + colC;
- if (usedIds.contains(lastId))
- lastId = -1;
- else
- break;
- }
- }
- break;
- }// BC
- case 2: {
- if (rowC < LockPatternView.MATRIX_WIDTH) {
- randomValues = Randoms.randIntArray(Math.max(0,
- colA), Math.min(
- LockPatternView.MATRIX_WIDTH, colC));
- for (int c : randomValues) {
- lastId = rowC * LockPatternView.MATRIX_WIDTH
- + c;
- if (usedIds.contains(lastId))
- lastId = -1;
- else
- break;
- }
- }
- break;
- }// DC
- case 3: {
- if (colA >= 0) {
- randomValues = Randoms.randIntArray(Math.max(0,
- rowA + 1), Math.min(
- LockPatternView.MATRIX_WIDTH, rowC));
- for (int r : randomValues) {
- lastId = r * LockPatternView.MATRIX_WIDTH
- + colA;
- if (usedIds.contains(lastId))
- lastId = -1;
- else
- break;
- }
- }
- break;
- }// AD
- }
-
- if (lastId >= 0)
- break;
- }// for line
-
- if (lastId >= 0)
- break;
- }// for distance
-
- usedIds.add(lastId);
- }// while
-
- final ArrayList result = Lists.newArrayList();
- for (int id : usedIds)
- result.add(LockPatternView.Cell.of(id));
-
- return result;
- }// genCaptchaPattern()
-
-}
diff --git a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/widget/LockPatternView.java b/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/widget/LockPatternView.java
deleted file mode 100644
index 1a1f652..0000000
--- a/source-android-studio/app/src/main/java/com/haibison/android/lockpattern/widget/LockPatternView.java
+++ /dev/null
@@ -1,1368 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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.haibison.android.lockpattern.widget;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.Debug;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.view.HapticFeedbackConstants;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.haibison.android.lockpattern.R;
-import com.haibison.android.lockpattern.util.FloatAnimator;
-import com.haibison.android.lockpattern.util.ResourceUtils;
-
-/**
- * Displays and detects the user's unlock attempt, which is a drag of a finger
- * across 9 regions of the screen.
- *
- * Is also capable of displaying a static pattern in "in progress", "wrong" or
- * "correct" states.
- */
-public class LockPatternView extends View {
-
- /**
- * Represents a cell in the MATRIX_WIDTH x MATRIX_WIDTH matrix of the unlock
- * pattern view.
- */
- public static class Cell implements Parcelable {
-
- /**
- * Row.
- */
- public final int row;
-
- /**
- * Column.
- */
- public final int column;
-
- /*
- * keep # objects limited to MATRIX_SIZE
- */
- static Cell[][] sCells = new Cell[MATRIX_WIDTH][MATRIX_WIDTH];
- static {
- for (int i = 0; i < MATRIX_WIDTH; i++) {
- for (int j = 0; j < MATRIX_WIDTH; j++) {
- sCells[i][j] = new Cell(i, j);
- }
- }
- }
-
- /**
- * @param row
- * The row of the cell.
- * @param column
- * The column of the cell.
- */
- private Cell(int row, int column) {
- checkRange(row, column);
- this.row = row;
- this.column = column;
- }
-
- /**
- * Gets the ID.It is counted from left to right, top to bottom of the
- * matrix, starting by zero.
- *
- * @return the ID.
- */
- public int getId() {
- return row * MATRIX_WIDTH + column;
- }// getId()
-
- /**
- * @param row
- * The row of the cell.
- * @param column
- * The column of the cell.
- */
- public static synchronized Cell of(int row, int column) {
- checkRange(row, column);
- return sCells[row][column];
- }
-
- /**
- * Gets a cell from its ID.
- *
- * @param id
- * the cell ID.
- * @return the cell.
- * @since v2.7 beta
- * @author Hai Bison
- */
- public static synchronized Cell of(int id) {
- return of(id / MATRIX_WIDTH, id % MATRIX_WIDTH);
- }// of()
-
- private static void checkRange(int row, int column) {
- if (row < 0 || row > MATRIX_WIDTH - 1) {
- throw new IllegalArgumentException("row must be in range 0-"
- + (MATRIX_WIDTH - 1));
- }
- if (column < 0 || column > MATRIX_WIDTH - 1) {
- throw new IllegalArgumentException("column must be in range 0-"
- + (MATRIX_WIDTH - 1));
- }
- }
-
- @Override
- public String toString() {
- return "(ROW=" + row + ",COL=" + column + ")";
- }// toString()
-
- @Override
- public boolean equals(Object object) {
- if (object instanceof Cell)
- return column == ((Cell) object).column
- && row == ((Cell) object).row;
- return super.equals(object);
- }// equals()
-
- /*
- * PARCELABLE
- */
-
- @Override
- public int describeContents() {
- return 0;
- }// describeContents()
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(column);
- dest.writeInt(row);
- }// writeToParcel()
-
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
-
- public Cell createFromParcel(Parcel in) {
- return new Cell(in);
- }// createFromParcel()
-
- public Cell[] newArray(int size) {
- return new Cell[size];
- }// newArray()
- };// CREATOR
-
- private Cell(Parcel in) {
- column = in.readInt();
- row = in.readInt();
- }// Cell()
-
- }// Cell
-
- /**
- * How to display the current pattern.
- */
- public enum DisplayMode {
-
- /**
- * The pattern drawn is correct (i.e draw it in a friendly color)
- */
- Correct,
-
- /**
- * Animate the pattern (for demo, and help).
- */
- Animate,
-
- /**
- * The pattern is wrong (i.e draw a foreboding color)
- */
- Wrong
- }
-
- /**
- * The call back interface for detecting patterns entered by the user.
- */
- public static interface OnPatternListener {
-
- /**
- * A new pattern has begun.
- */
- void onPatternStart();
-
- /**
- * The pattern was cleared.
- */
- void onPatternCleared();
-
- /**
- * The user extended the pattern currently being drawn by one cell.
- *
- * @param pattern
- * The pattern with newly added cell.
- */
- void onPatternCellAdded(List pattern);
-
- /**
- * A pattern was detected from the user.
- *
- * @param pattern
- * The pattern.
- */
- void onPatternDetected(List pattern);
- }
-
- // Aspect to use when rendering this view
- private static final int ASPECT_SQUARE = 0; // View will be the minimum of
- // width/height
- private static final int ASPECT_LOCK_WIDTH = 1; // Fixed width; height will
- // be minimum of (w,h)
- private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will
- // be minimum of (w,h)
-
- /**
- * This is the width of the matrix (the number of dots per row and column).
- * Change this value to change the dimension of the pattern's matrix.
- *
- * @since v2.7 beta
- * @author Thomas Breitbach
- */
- public static final int MATRIX_WIDTH = 3;
-
- /**
- * The size of the pattern's matrix.
- */
- public static final int MATRIX_SIZE = MATRIX_WIDTH * MATRIX_WIDTH;
-
- private static final boolean PROFILE_DRAWING = false;
- private final CellState[][] mCellStates;
-
- private final int mDotSize;
- private final int mDotSizeActivated;
- private final int mPathWidth;
-
- private boolean mDrawingProfilingStarted = false;
-
- private Paint mPaint = new Paint();
- private Paint mPathPaint = new Paint();
-
- /**
- * How many milliseconds we spend animating each circle of a lock pattern if
- * the animating mode is set. The entire animation should take this constant
- * * the length of the pattern to complete.
- */
- private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
-
- /**
- * This can be used to avoid updating the display for very small motions or
- * noisy panels. It didn't seem to have much impact on the devices tested,
- * so currently set to 0.
- */
- private static final float DRAG_THRESHHOLD = 0.0f;
-
- private OnPatternListener mOnPatternListener;
- private ArrayList mPattern = new ArrayList(MATRIX_SIZE);
-
- /**
- * Lookup table for the circles of the pattern we are currently drawing.
- * This will be the cells of the complete pattern unless we are animating,
- * in which case we use this to hold the cells we are drawing for the in
- * progress animation.
- */
- private boolean[][] mPatternDrawLookup = new boolean[MATRIX_WIDTH][MATRIX_WIDTH];
-
- /**
- * the in progress point: - during interaction: where the user's finger is -
- * during animation: the current tip of the animating line
- */
- private float mInProgressX = -1;
- private float mInProgressY = -1;
-
- private long mAnimatingPeriodStart;
-
- private DisplayMode mPatternDisplayMode = DisplayMode.Correct;
- private boolean mInputEnabled = true;
- private boolean mInStealthMode = false;
- private boolean mEnableHapticFeedback = true;
- private boolean mPatternInProgress = false;
-
- private float mHitFactor = 0.6f;
-
- private float mSquareWidth;
- private float mSquareHeight;
-
- private final Path mCurrentPath = new Path();
- private final Rect mInvalidate = new Rect();
- private final Rect mTmpInvalidateRect = new Rect();
-
- private int mAspect;
- private int mRegularColor;
- private int mErrorColor;
- private int mSuccessColor;
-
- private Interpolator mFastOutSlowInInterpolator;
- private Interpolator mLinearOutSlowInInterpolator;
-
- public static class CellState {
-
- public float scale = 1.0f;
- public float translateY = 0.0f;
- public float alpha = 1.0f;
- public float size;
- public float lineEndX = Float.MIN_VALUE;
- public float lineEndY = Float.MIN_VALUE;
- public ValueAnimator lineAnimator;
- }
-
- public LockPatternView(Context context) {
- this(context, null);
- }
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public LockPatternView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.Alp_42447968_LockPatternView);
-
- final String aspect = a
- .getString(R.styleable.Alp_42447968_LockPatternView_aspect);
-
- if ("square".equals(aspect)) {
- mAspect = ASPECT_SQUARE;
- } else if ("lock_width".equals(aspect)) {
- mAspect = ASPECT_LOCK_WIDTH;
- } else if ("lock_height".equals(aspect)) {
- mAspect = ASPECT_LOCK_HEIGHT;
- } else {
- mAspect = ASPECT_SQUARE;
- }
-
- setClickable(true);
-
- mPathPaint.setAntiAlias(true);
- mPathPaint.setDither(true);
-
- mRegularColor = getResources().getColor(
- ResourceUtils.resolveAttribute(getContext(),
- R.attr.alp_42447968_color_lock_pattern_view_regular));
- mErrorColor = getResources().getColor(
- ResourceUtils.resolveAttribute(getContext(),
- R.attr.alp_42447968_color_lock_pattern_view_error));
- mSuccessColor = getResources().getColor(
- ResourceUtils.resolveAttribute(getContext(),
- R.attr.alp_42447968_color_lock_pattern_view_success));
-
- mRegularColor = a.getColor(
- R.styleable.Alp_42447968_LockPatternView_regularColor,
- mRegularColor);
- mErrorColor = a.getColor(
- R.styleable.Alp_42447968_LockPatternView_errorColor,
- mErrorColor);
- mSuccessColor = a.getColor(
- R.styleable.Alp_42447968_LockPatternView_successColor,
- mSuccessColor);
-
- int pathColor = a.getColor(
- R.styleable.Alp_42447968_LockPatternView_pathColor,
- mRegularColor);
- mPathPaint.setColor(pathColor);
-
- mPathPaint.setStyle(Paint.Style.STROKE);
- mPathPaint.setStrokeJoin(Paint.Join.ROUND);
- mPathPaint.setStrokeCap(Paint.Cap.ROUND);
-
- mPathWidth = getResources().getDimensionPixelSize(
- R.dimen.alp_42447968_lock_pattern_dot_line_width);
- mPathPaint.setStrokeWidth(mPathWidth);
-
- mDotSize = getResources().getDimensionPixelSize(
- R.dimen.alp_42447968_lock_pattern_dot_size);
- mDotSizeActivated = getResources().getDimensionPixelSize(
- R.dimen.alp_42447968_lock_pattern_dot_size_activated);
-
- mPaint.setAntiAlias(true);
- mPaint.setDither(true);
-
- mCellStates = new CellState[MATRIX_WIDTH][MATRIX_WIDTH];
- for (int i = 0; i < MATRIX_WIDTH; i++) {
- for (int j = 0; j < MATRIX_WIDTH; j++) {
- mCellStates[i][j] = new CellState();
- mCellStates[i][j].size = mDotSize;
- }
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- context, android.R.interpolator.fast_out_slow_in);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- context, android.R.interpolator.linear_out_slow_in);
- }// if
- }// LockPatternView_v11()
-
- public CellState[][] getCellStates() {
- return mCellStates;
- }
-
- /**
- * @return Whether the view is in stealth mode.
- */
- public boolean isInStealthMode() {
- return mInStealthMode;
- }
-
- /**
- * @return Whether the view has tactile feedback enabled.
- */
- public boolean isTactileFeedbackEnabled() {
- return mEnableHapticFeedback;
- }
-
- /**
- * Set whether the view is in stealth mode. If {@code true}, there will be
- * no visible feedback as the user enters the pattern.
- *
- * @param inStealthMode
- * Whether in stealth mode.
- */
- public void setInStealthMode(boolean inStealthMode) {
- mInStealthMode = inStealthMode;
- }
-
- /**
- * Set whether the view will use tactile feedback. If {@code true}, there
- * will be tactile feedback as the user enters the pattern.
- *
- * @param tactileFeedbackEnabled
- * Whether tactile feedback is enabled
- */
- public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) {
- mEnableHapticFeedback = tactileFeedbackEnabled;
- }
-
- /**
- * Set the call back for pattern detection.
- *
- * @param onPatternListener
- * The call back.
- */
- public void setOnPatternListener(OnPatternListener onPatternListener) {
- mOnPatternListener = onPatternListener;
- }
-
- /**
- * Retrieves current pattern.
- *
- * @return current displaying pattern. Note: This is an independent
- * list with the view's pattern itself.
- */
- @SuppressWarnings("unchecked")
- public List getPattern() {
- return (List) mPattern.clone();
- }// getPattern()
-
- /**
- * Set the pattern explicitely (rather than waiting for the user to input a
- * pattern).
- *
- * @param displayMode
- * How to display the pattern.
- * @param pattern
- * The pattern.
- */
- public void setPattern(DisplayMode displayMode, List pattern) {
- mPattern.clear();
- mPattern.addAll(pattern);
- clearPatternDrawLookup();
- for (Cell cell : pattern) {
- mPatternDrawLookup[cell.row][cell.column] = true;
- }
-
- setDisplayMode(displayMode);
- }
-
- /**
- * Gets display mode.
- *
- * @return display mode.
- */
- public DisplayMode getDisplayMode() {
- return mPatternDisplayMode;
- }// getDisplayMode()
-
- /**
- * Set the display mode of the current pattern. This can be useful, for
- * instance, after detecting a pattern to tell this view whether change the
- * in progress result to correct or wrong.
- *
- * @param displayMode
- * The display mode.
- */
- public void setDisplayMode(DisplayMode displayMode) {
- mPatternDisplayMode = displayMode;
- if (displayMode == DisplayMode.Animate) {
- if (mPattern.size() == 0) {
- throw new IllegalStateException(
- "you must have a pattern to "
- + "animate if you want to set the display mode to animate");
- }
- mAnimatingPeriodStart = SystemClock.elapsedRealtime();
- final Cell first = mPattern.get(0);
- mInProgressX = getCenterXForColumn(first.column);
- mInProgressY = getCenterYForRow(first.row);
- clearPatternDrawLookup();
- }
- invalidate();
- }
-
- private void notifyCellAdded() {
- sendAccessEvent(R.string.alp_42447968_lockscreen_access_pattern_cell_added);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternCellAdded(mPattern);
- }
- }
-
- private void notifyPatternStarted() {
- sendAccessEvent(R.string.alp_42447968_lockscreen_access_pattern_start);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternStart();
- }
- }
-
- private void notifyPatternDetected() {
- sendAccessEvent(R.string.alp_42447968_lockscreen_access_pattern_detected);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternDetected(mPattern);
- }
- }
-
- private void notifyPatternCleared() {
- sendAccessEvent(R.string.alp_42447968_lockscreen_access_pattern_cleared);
- if (mOnPatternListener != null) {
- mOnPatternListener.onPatternCleared();
- }
- }
-
- /**
- * Clear the pattern.
- */
- public void clearPattern() {
- resetPattern();
- }
-
- /**
- * Reset all pattern state.
- */
- private void resetPattern() {
- mPattern.clear();
- clearPatternDrawLookup();
- mPatternDisplayMode = DisplayMode.Correct;
- invalidate();
- }
-
- /**
- * Clear the pattern lookup table.
- */
- private void clearPatternDrawLookup() {
- for (int i = 0; i < MATRIX_WIDTH; i++) {
- for (int j = 0; j < MATRIX_WIDTH; j++) {
- mPatternDrawLookup[i][j] = false;
- }
- }
- }
-
- /**
- * Disable input (for instance when displaying a message that will timeout
- * so user doesn't get view into messy state).
- */
- public void disableInput() {
- mInputEnabled = false;
- }
-
- /**
- * Enable input.
- */
- public void enableInput() {
- mInputEnabled = true;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- final int width = w - getPaddingLeft() - getPaddingRight();
- mSquareWidth = width / (float) MATRIX_WIDTH;
-
- final int height = h - getPaddingTop() - getPaddingBottom();
- mSquareHeight = height / (float) MATRIX_WIDTH;
- }
-
- private int resolveMeasured(int measureSpec, int desired) {
- int result = 0;
- int specSize = MeasureSpec.getSize(measureSpec);
- switch (MeasureSpec.getMode(measureSpec)) {
- case MeasureSpec.UNSPECIFIED:
- result = desired;
- break;
- case MeasureSpec.AT_MOST:
- result = Math.max(specSize, desired);
- break;
- case MeasureSpec.EXACTLY:
- default:
- result = specSize;
- }
- return result;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int minimumWidth = getSuggestedMinimumWidth();
- final int minimumHeight = getSuggestedMinimumHeight();
- int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
- int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
-
- switch (mAspect) {
- case ASPECT_SQUARE:
- viewWidth = viewHeight = Math.min(viewWidth, viewHeight);
- break;
- case ASPECT_LOCK_WIDTH:
- viewHeight = Math.min(viewWidth, viewHeight);
- break;
- case ASPECT_LOCK_HEIGHT:
- viewWidth = Math.min(viewWidth, viewHeight);
- break;
- }
- // Log.v(TAG, "LockPatternView dimensions: " + viewWidth + "x" +
- // viewHeight);
- setMeasuredDimension(viewWidth, viewHeight);
- }
-
- /**
- * Determines whether the point x, y will add a new point to the current
- * pattern (in addition to finding the cell, also makes heuristic choices
- * such as filling in gaps based on current pattern).
- *
- * @param x
- * The x coordinate.
- * @param y
- * The y coordinate.
- */
- @TargetApi(Build.VERSION_CODES.ECLAIR)
- private Cell detectAndAddHit(float x, float y) {
- final Cell cell = checkForNewHit(x, y);
- if (cell != null) {
-
- // check for gaps in existing pattern
- Cell fillInGapCell = null;
- final ArrayList pattern = mPattern;
- if (!pattern.isEmpty()) {
- final Cell lastCell = pattern.get(pattern.size() - 1);
- int dRow = cell.row - lastCell.row;
- int dColumn = cell.column - lastCell.column;
-
- int fillInRow = lastCell.row;
- int fillInColumn = lastCell.column;
-
- if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) {
- fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1);
- }
-
- if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) {
- fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1);
- }
-
- fillInGapCell = Cell.of(fillInRow, fillInColumn);
- }
-
- if (fillInGapCell != null
- && !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
- addCellToPattern(fillInGapCell);
- }
- addCellToPattern(cell);
- if (mEnableHapticFeedback) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR)
- performHapticFeedback(
- HapticFeedbackConstants.VIRTUAL_KEY,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
- | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
- }
- return cell;
- }
- return null;
- }
-
- private void addCellToPattern(Cell newCell) {
- mPatternDrawLookup[newCell.row][newCell.column] = true;
- mPattern.add(newCell);
- if (!mInStealthMode) {
- startCellActivatedAnimation(newCell);
- }
- notifyCellAdded();
- }
-
- private void startCellActivatedAnimation(Cell cell) {
- final CellState cellState = mCellStates[cell.row][cell.column];
- startSizeAnimation(mDotSize, mDotSizeActivated, 96,
- mLinearOutSlowInInterpolator, cellState, new Runnable() {
-
- @Override
- public void run() {
- startSizeAnimation(mDotSizeActivated, mDotSize, 192,
- mFastOutSlowInInterpolator, cellState, null);
- }
- });
- startLineEndAnimation(cellState, mInProgressX, mInProgressY,
- getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
- }
-
- private void startLineEndAnimation(final CellState state,
- final float startX, final float startY, final float targetX,
- final float targetY) {
- /*
- * Currently this animation looks unclear, we don't really need it...
- */
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
- return;
-
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
- valueAnimator
- .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float t = (Float) animation.getAnimatedValue();
- state.lineEndX = (1 - t) * startX + t * targetX;
- state.lineEndY = (1 - t) * startY + t * targetY;
- invalidate();
- }
-
- });
- valueAnimator.addListener(new AnimatorListenerAdapter() {
-
- @Override
- public void onAnimationEnd(Animator animation) {
- state.lineAnimator = null;
- }
-
- });
- valueAnimator.setInterpolator(mFastOutSlowInInterpolator);
- valueAnimator.setDuration(100);
- valueAnimator.start();
- state.lineAnimator = valueAnimator;
- }
-
- private void startSizeAnimation(float start, float end, long duration,
- Interpolator interpolator, final CellState state,
- final Runnable endRunnable) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
- FloatAnimator animator = new FloatAnimator(start, end, duration);
- animator.addEventListener(new FloatAnimator.SimpleEventListener() {
-
- @Override
- public void onAnimationUpdate(FloatAnimator animator) {
- state.size = (Float) animator.getAnimatedValue();
- invalidate();
- }// onAnimationUpdate()
-
- @Override
- public void onAnimationEnd(FloatAnimator animator) {
- if (endRunnable != null)
- endRunnable.run();
- }// onAnimationEnd()
-
- });
- animator.start();
- }// API < 11
- else {
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
- valueAnimator
- .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- state.size = (Float) animation.getAnimatedValue();
- invalidate();
- }
-
- });
- if (endRunnable != null) {
- valueAnimator.addListener(new AnimatorListenerAdapter() {
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (endRunnable != null)
- endRunnable.run();
- }
-
- });
- }
- valueAnimator.setInterpolator(interpolator);
- valueAnimator.setDuration(duration);
- valueAnimator.start();
- }// API 11+
- }// startSizeAnimation()
-
- // helper method to find which cell a point maps to
- private Cell checkForNewHit(float x, float y) {
-
- final int rowHit = getRowHit(y);
- if (rowHit < 0) {
- return null;
- }
- final int columnHit = getColumnHit(x);
- if (columnHit < 0) {
- return null;
- }
-
- if (mPatternDrawLookup[rowHit][columnHit]) {
- return null;
- }
- return Cell.of(rowHit, columnHit);
- }
-
- /**
- * Helper method to find the row that y falls into.
- *
- * @param y
- * The y coordinate
- * @return The row that y falls in, or -1 if it falls in no row.
- */
- private int getRowHit(float y) {
-
- final float squareHeight = mSquareHeight;
- float hitSize = squareHeight * mHitFactor;
-
- float offset = getPaddingTop() + (squareHeight - hitSize) / 2f;
- for (int i = 0; i < MATRIX_WIDTH; i++) {
-
- final float hitTop = offset + squareHeight * i;
- if (y >= hitTop && y <= hitTop + hitSize) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Helper method to find the column x fallis into.
- *
- * @param x
- * The x coordinate.
- * @return The column that x falls in, or -1 if it falls in no column.
- */
- private int getColumnHit(float x) {
- final float squareWidth = mSquareWidth;
- float hitSize = squareWidth * mHitFactor;
-
- float offset = getPaddingLeft() + (squareWidth - hitSize) / 2f;
- for (int i = 0; i < MATRIX_WIDTH; i++) {
-
- final float hitLeft = offset + squareWidth * i;
- if (x >= hitLeft && x <= hitLeft + hitSize) {
- return i;
- }
- }
- return -1;
- }
-
- @Override
- public boolean onHoverEvent(MotionEvent event) {
- if (((AccessibilityManager) getContext().getSystemService(
- Context.ACCESSIBILITY_SERVICE)).isTouchExplorationEnabled()) {
- final int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_HOVER_ENTER:
- event.setAction(MotionEvent.ACTION_DOWN);
- break;
- case MotionEvent.ACTION_HOVER_MOVE:
- event.setAction(MotionEvent.ACTION_MOVE);
- break;
- case MotionEvent.ACTION_HOVER_EXIT:
- event.setAction(MotionEvent.ACTION_UP);
- break;
- }
- onTouchEvent(event);
- event.setAction(action);
- }
- return super.onHoverEvent(event);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!mInputEnabled || !isEnabled()) {
- return false;
- }
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- handleActionDown(event);
- return true;
- case MotionEvent.ACTION_UP:
- handleActionUp(event);
- return true;
- case MotionEvent.ACTION_MOVE:
- handleActionMove(event);
- return true;
- case MotionEvent.ACTION_CANCEL:
- /*
- * Original source check for mPatternInProgress == true first before
- * calling next three lines. But if we do that, there will be
- * nothing happened when the user taps at empty area and releases
- * the finger. We want the pattern to be reset and the message will
- * be updated after the user did that.
- */
- mPatternInProgress = false;
- resetPattern();
- notifyPatternCleared();
-
- if (PROFILE_DRAWING) {
- if (mDrawingProfilingStarted) {
- Debug.stopMethodTracing();
- mDrawingProfilingStarted = false;
- }
- }
- return true;
- }
- return false;
- }
-
- private void handleActionMove(MotionEvent event) {
- // Handle all recent motion events so we don't skip any cells even when
- // the device
- // is busy...
- final float radius = mPathWidth;
- final int historySize = event.getHistorySize();
- mTmpInvalidateRect.setEmpty();
- boolean invalidateNow = false;
- for (int i = 0; i < historySize + 1; i++) {
- final float x = i < historySize ? event.getHistoricalX(i) : event
- .getX();
- final float y = i < historySize ? event.getHistoricalY(i) : event
- .getY();
- Cell hitCell = detectAndAddHit(x, y);
- final int patternSize = mPattern.size();
- if (hitCell != null && patternSize == 1) {
- mPatternInProgress = true;
- notifyPatternStarted();
- }
- // note current x and y for rubber banding of in progress patterns
- final float dx = Math.abs(x - mInProgressX);
- final float dy = Math.abs(y - mInProgressY);
- if (dx > DRAG_THRESHHOLD || dy > DRAG_THRESHHOLD) {
- invalidateNow = true;
- }
-
- if (mPatternInProgress && patternSize > 0) {
- final ArrayList pattern = mPattern;
- final Cell lastCell = pattern.get(patternSize - 1);
- float lastCellCenterX = getCenterXForColumn(lastCell.column);
- float lastCellCenterY = getCenterYForRow(lastCell.row);
-
- // Adjust for drawn segment from last cell to (x,y). Radius
- // accounts for line width.
- float left = Math.min(lastCellCenterX, x) - radius;
- float right = Math.max(lastCellCenterX, x) + radius;
- float top = Math.min(lastCellCenterY, y) - radius;
- float bottom = Math.max(lastCellCenterY, y) + radius;
-
- // Invalidate between the pattern's new cell and the pattern's
- // previous cell
- if (hitCell != null) {
- final float width = mSquareWidth * 0.5f;
- final float height = mSquareHeight * 0.5f;
- final float hitCellCenterX = getCenterXForColumn(hitCell.column);
- final float hitCellCenterY = getCenterYForRow(hitCell.row);
-
- left = Math.min(hitCellCenterX - width, left);
- right = Math.max(hitCellCenterX + width, right);
- top = Math.min(hitCellCenterY - height, top);
- bottom = Math.max(hitCellCenterY + height, bottom);
- }
-
- // Invalidate between the pattern's last cell and the previous
- // location
- mTmpInvalidateRect.union(Math.round(left), Math.round(top),
- Math.round(right), Math.round(bottom));
- }
- }
- mInProgressX = event.getX();
- mInProgressY = event.getY();
-
- // To save updates, we only invalidate if the user moved beyond a
- // certain amount.
- if (invalidateNow) {
- mInvalidate.union(mTmpInvalidateRect);
- invalidate(mInvalidate);
- mInvalidate.set(mTmpInvalidateRect);
- }
- }
-
- private void sendAccessEvent(int resId) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
- setContentDescription(getContext().getString(resId));
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
- setContentDescription(null);
- } else
- announceForAccessibility(getContext().getString(resId));
- }
-
- private void handleActionUp(MotionEvent event) {
- // report pattern detected
- if (!mPattern.isEmpty()) {
- mPatternInProgress = false;
- cancelLineAnimations();
- notifyPatternDetected();
- invalidate();
- }
- if (PROFILE_DRAWING) {
- if (mDrawingProfilingStarted) {
- Debug.stopMethodTracing();
- mDrawingProfilingStarted = false;
- }
- }
- }
-
- private void cancelLineAnimations() {
- for (int i = 0; i < MATRIX_WIDTH; i++) {
- for (int j = 0; j < MATRIX_WIDTH; j++) {
- CellState state = mCellStates[i][j];
- if (state.lineAnimator != null) {
- state.lineAnimator.cancel();
- state.lineEndX = Float.MIN_VALUE;
- state.lineEndY = Float.MIN_VALUE;
- }
- }
- }
- }
-
- private void handleActionDown(MotionEvent event) {
- resetPattern();
- final float x = event.getX();
- final float y = event.getY();
- final Cell hitCell = detectAndAddHit(x, y);
- if (hitCell != null) {
- mPatternInProgress = true;
- mPatternDisplayMode = DisplayMode.Correct;
- notifyPatternStarted();
- } else {
- /*
- * Original source check for mPatternInProgress == true first before
- * calling this block. But if we do that, there will be nothing
- * happened when the user taps at empty area and releases the
- * finger. We want the pattern to be reset and the message will be
- * updated after the user did that.
- */
- mPatternInProgress = false;
- notifyPatternCleared();
- }
- if (hitCell != null) {
- final float startX = getCenterXForColumn(hitCell.column);
- final float startY = getCenterYForRow(hitCell.row);
-
- final float widthOffset = mSquareWidth / 2f;
- final float heightOffset = mSquareHeight / 2f;
-
- invalidate((int) (startX - widthOffset),
- (int) (startY - heightOffset),
- (int) (startX + widthOffset), (int) (startY + heightOffset));
- }
- mInProgressX = x;
- mInProgressY = y;
- if (PROFILE_DRAWING) {
- if (!mDrawingProfilingStarted) {
- Debug.startMethodTracing("LockPatternDrawing");
- mDrawingProfilingStarted = true;
- }
- }
- }
-
- private float getCenterXForColumn(int column) {
- return getPaddingLeft() + column * mSquareWidth + mSquareWidth / 2f;
- }
-
- private float getCenterYForRow(int row) {
- return getPaddingTop() + row * mSquareHeight + mSquareHeight / 2f;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- final ArrayList pattern = mPattern;
- final int count = pattern.size();
- final boolean[][] drawLookup = mPatternDrawLookup;
-
- if (mPatternDisplayMode == DisplayMode.Animate) {
-
- // figure out which circles to draw
-
- // + 1 so we pause on complete pattern
- final int oneCycle = (count + 1) * MILLIS_PER_CIRCLE_ANIMATING;
- final int spotInCycle = (int) (SystemClock.elapsedRealtime() - mAnimatingPeriodStart)
- % oneCycle;
- final int numCircles = spotInCycle / MILLIS_PER_CIRCLE_ANIMATING;
-
- clearPatternDrawLookup();
- for (int i = 0; i < numCircles; i++) {
- final Cell cell = pattern.get(i);
- drawLookup[cell.row][cell.column] = true;
- }
-
- // figure out in progress portion of ghosting line
-
- final boolean needToUpdateInProgressPoint = numCircles > 0
- && numCircles < count;
-
- if (needToUpdateInProgressPoint) {
- final float percentageOfNextCircle = ((float) (spotInCycle % MILLIS_PER_CIRCLE_ANIMATING))
- / MILLIS_PER_CIRCLE_ANIMATING;
-
- final Cell currentCell = pattern.get(numCircles - 1);
- final float centerX = getCenterXForColumn(currentCell.column);
- final float centerY = getCenterYForRow(currentCell.row);
-
- final Cell nextCell = pattern.get(numCircles);
- final float dx = percentageOfNextCircle
- * (getCenterXForColumn(nextCell.column) - centerX);
- final float dy = percentageOfNextCircle
- * (getCenterYForRow(nextCell.row) - centerY);
- mInProgressX = centerX + dx;
- mInProgressY = centerY + dy;
- }
- // TODO: Infinite loop here...
- invalidate();
- }
-
- final Path currentPath = mCurrentPath;
- currentPath.rewind();
-
- // draw the circles
- for (int i = 0; i < MATRIX_WIDTH; i++) {
- float centerY = getCenterYForRow(i);
- for (int j = 0; j < MATRIX_WIDTH; j++) {
- CellState cellState = mCellStates[i][j];
- float centerX = getCenterXForColumn(j);
- float size = cellState.size * cellState.scale;
- float translationY = cellState.translateY;
- drawCircle(canvas, (int) centerX, (int) centerY + translationY,
- size, drawLookup[i][j], cellState.alpha);
- }
- }
-
- // TODO: the path should be created and cached every time we hit-detect
- // a cell
- // only the last segment of the path should be computed here
- // draw the path of the pattern (unless we are in stealth mode)
- final boolean drawPath = !mInStealthMode;
-
- if (drawPath) {
- mPathPaint.setColor(getCurrentColor(true /* partOfPattern */));
-
- boolean anyCircles = false;
- float lastX = 0f;
- float lastY = 0f;
- for (int i = 0; i < count; i++) {
- Cell cell = pattern.get(i);
-
- // only draw the part of the pattern stored in
- // the lookup table (this is only different in the case
- // of animation).
- if (!drawLookup[cell.row][cell.column]) {
- break;
- }
- anyCircles = true;
-
- float centerX = getCenterXForColumn(cell.column);
- float centerY = getCenterYForRow(cell.row);
- if (i != 0) {
- CellState state = mCellStates[cell.row][cell.column];
- currentPath.rewind();
- currentPath.moveTo(lastX, lastY);
- if (state.lineEndX != Float.MIN_VALUE
- && state.lineEndY != Float.MIN_VALUE) {
- currentPath.lineTo(state.lineEndX, state.lineEndY);
- } else {
- currentPath.lineTo(centerX, centerY);
- }
- canvas.drawPath(currentPath, mPathPaint);
- }
- lastX = centerX;
- lastY = centerY;
- }
-
- // draw last in progress section
- if ((mPatternInProgress || mPatternDisplayMode == DisplayMode.Animate)
- && anyCircles) {
- currentPath.rewind();
- currentPath.moveTo(lastX, lastY);
- currentPath.lineTo(mInProgressX, mInProgressY);
-
- mPathPaint.setAlpha((int) (calculateLastSegmentAlpha(
- mInProgressX, mInProgressY, lastX, lastY) * 255f));
- canvas.drawPath(currentPath, mPathPaint);
- }
- }
- }
-
- private float calculateLastSegmentAlpha(float x, float y, float lastX,
- float lastY) {
- float diffX = x - lastX;
- float diffY = y - lastY;
- float dist = (float) Math.sqrt(diffX * diffX + diffY * diffY);
- float frac = dist / mSquareWidth;
- return Math.min(1f, Math.max(0f, (frac - 0.3f) * 4f));
- }
-
- private int getCurrentColor(boolean partOfPattern) {
- if (!partOfPattern || mInStealthMode || mPatternInProgress) {
- // unselected circle
- return mRegularColor;
- } else if (mPatternDisplayMode == DisplayMode.Wrong) {
- // the pattern is wrong
- return mErrorColor;
- } else if (mPatternDisplayMode == DisplayMode.Correct
- || mPatternDisplayMode == DisplayMode.Animate) {
- return mSuccessColor;
- } else {
- throw new IllegalStateException("unknown display mode "
- + mPatternDisplayMode);
- }
- }
-
- /**
- * @param partOfPattern
- * Whether this circle is part of the pattern.
- */
- private void drawCircle(Canvas canvas, float centerX, float centerY,
- float size, boolean partOfPattern, float alpha) {
- mPaint.setColor(getCurrentColor(partOfPattern));
- mPaint.setAlpha((int) (alpha * 255));
- canvas.drawCircle(centerX, centerY, size / 2, mPaint);
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
- return new SavedState(superState,
- LockPatternUtils.patternToString(mPattern),
- mPatternDisplayMode.ordinal(), mInputEnabled, mInStealthMode,
- mEnableHapticFeedback);
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- final SavedState ss = (SavedState) state;
- super.onRestoreInstanceState(ss.getSuperState());
- setPattern(DisplayMode.Correct,
- LockPatternUtils.stringToPattern(ss.getSerializedPattern()));
- mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()];
- mInputEnabled = ss.isInputEnabled();
- mInStealthMode = ss.isInStealthMode();
- mEnableHapticFeedback = ss.isTactileFeedbackEnabled();
- }
-
- /**
- * The parecelable for saving and restoring a lock pattern view.
- */
- private static class SavedState extends BaseSavedState {
-
- private final String mSerializedPattern;
- private final int mDisplayMode;
- private final boolean mInputEnabled;
- private final boolean mInStealthMode;
- private final boolean mTactileFeedbackEnabled;
-
- /**
- * Constructor called from {@link LockPatternView#onSaveInstanceState()}
- */
- private SavedState(Parcelable superState, String serializedPattern,
- int displayMode, boolean inputEnabled, boolean inStealthMode,
- boolean tactileFeedbackEnabled) {
- super(superState);
- mSerializedPattern = serializedPattern;
- mDisplayMode = displayMode;
- mInputEnabled = inputEnabled;
- mInStealthMode = inStealthMode;
- mTactileFeedbackEnabled = tactileFeedbackEnabled;
- }
-
- /**
- * Constructor called from {@link #CREATOR}
- */
- private SavedState(Parcel in) {
- super(in);
- mSerializedPattern = in.readString();
- mDisplayMode = in.readInt();
- mInputEnabled = (Boolean) in.readValue(null);
- mInStealthMode = (Boolean) in.readValue(null);
- mTactileFeedbackEnabled = (Boolean) in.readValue(null);
- }
-
- public String getSerializedPattern() {
- return mSerializedPattern;
- }
-
- public int getDisplayMode() {
- return mDisplayMode;
- }
-
- public boolean isInputEnabled() {
- return mInputEnabled;
- }
-
- public boolean isInStealthMode() {
- return mInStealthMode;
- }
-
- public boolean isTactileFeedbackEnabled() {
- return mTactileFeedbackEnabled;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeString(mSerializedPattern);
- dest.writeInt(mDisplayMode);
- dest.writeValue(mInputEnabled);
- dest.writeValue(mInStealthMode);
- dest.writeValue(mTactileFeedbackEnabled);
- }
-
- @SuppressWarnings("unused")
- public static final Parcelable.Creator CREATOR = new Creator() {
-
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-
-}
diff --git a/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png b/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png
deleted file mode 100644
index 911f3fe..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_light.9.png b/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_light.9.png
deleted file mode 100644
index 2129567..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_aosp_dialog_full_holo_light.9.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_dark.png b/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_dark.png
deleted file mode 100644
index 7c1ed6c..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_dark.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_light.png b/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_light.png
deleted file mode 100644
index 33e8b5f..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-hdpi/alp_42447968_ic_action_lockpattern_light.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png b/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png
deleted file mode 100644
index dc37316..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_light.9.png b/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_light.9.png
deleted file mode 100644
index 0c5770a..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_aosp_dialog_full_holo_light.9.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_dark.png b/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_dark.png
deleted file mode 100644
index a9c7e7e..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_dark.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_light.png b/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_light.png
deleted file mode 100644
index 8accd81..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-mdpi/alp_42447968_ic_action_lockpattern_light.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png b/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png
deleted file mode 100644
index 75d36be..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png b/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png
deleted file mode 100644
index d9bd337..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_dark.png b/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_dark.png
deleted file mode 100644
index 5c75350..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_dark.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_light.png b/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_light.png
deleted file mode 100644
index ab562aa..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-xhdpi/alp_42447968_ic_action_lockpattern_light.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png b/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png
deleted file mode 100644
index b029809..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_dark.9.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png b/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png
deleted file mode 100644
index 63dd192..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_aosp_dialog_full_holo_light.9.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_dark.png b/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_dark.png
deleted file mode 100644
index d936723..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_dark.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_light.png b/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_light.png
deleted file mode 100644
index c0a5cd8..0000000
Binary files a/source-android-studio/app/src/main/res/drawable-xxhdpi/alp_42447968_ic_action_lockpattern_light.png and /dev/null differ
diff --git a/source-android-studio/app/src/main/res/layout/alp_42447968_lock_pattern_activity.xml b/source-android-studio/app/src/main/res/layout/alp_42447968_lock_pattern_activity.xml
deleted file mode 100644
index 5dbb8f1..0000000
--- a/source-android-studio/app/src/main/res/layout/alp_42447968_lock_pattern_activity.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/layout/alp_42447968_lock_pattern_activity_land.xml b/source-android-studio/app/src/main/res/layout/alp_42447968_lock_pattern_activity_land.xml
deleted file mode 100644
index 8cf508a..0000000
--- a/source-android-studio/app/src/main/res/layout/alp_42447968_lock_pattern_activity_land.xml
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/layout/alp_42447968_view_group_progress_bar.xml b/source-android-studio/app/src/main/res/layout/alp_42447968_view_group_progress_bar.xml
deleted file mode 100644
index e4788bf..0000000
--- a/source-android-studio/app/src/main/res/layout/alp_42447968_view_group_progress_bar.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values-de/strings.xml b/source-android-studio/app/src/main/res/values-de/strings.xml
deleted file mode 100644
index c85782f..0000000
--- a/source-android-studio/app/src/main/res/values-de/strings.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
-
-
-
-
- Bestätigen
- Weiter
- Muster vergessen?
- Wiederholen
- Wird geladen…
- Zelle hinzugefügt
- Muster gelöscht
- Muster abgeschlossen
- Entsperrungsmuster gestartet
- Verbinde mind. 4 Punkte.\nVersuche es bitte erneut…
- Zeichne Entsperrungsmuster:
- Zum Entsperren Muster zeichnen:
- Muster aufgezeichnet!
- Muster wiederholen:
- Loslassen wenn fertig
- Entschuldigung, bitte erneut versuchen.
- Dein neues Entsperrungsmuster:
-
-
- Verbinde mind. %1$d Punkt.\nVersuche es bitte erneut…
- Verbinde mind. %1$d Punkte.\nVersuche es bitte erneut…
-
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values-en/strings.xml b/source-android-studio/app/src/main/res/values-en/strings.xml
deleted file mode 100644
index 6017fbc..0000000
--- a/source-android-studio/app/src/main/res/values-en/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
- Confirm
- Continue
- Forgot pattern?
- Retry
- Loading…
- Cell added
- Pattern cleared
- Pattern completed
- Pattern started
- Connect at least 4 dots.\nTry again…
- Draw an unlock pattern:
- Draw pattern to unlock:
- Pattern recorded!
- Redraw pattern to confirm:
- Release finger when done
- Sorry, try again
- Your new unlock pattern:
-
-
- Connect at least %1$d dot.\nTry again…
- Connect at least %1$d dots.\nTry again…
-
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values-es/strings.xml b/source-android-studio/app/src/main/res/values-es/strings.xml
deleted file mode 100644
index 4bacf50..0000000
--- a/source-android-studio/app/src/main/res/values-es/strings.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
-
-
-
-
- Confirmar
- Continuar
- ¿Has olvidado el patrón?
- Reintentar
- Cargando…
- Celda añadida
- Patrón limpiado
- Patrón completado
- Patrón empezado
- Conecta al menos 4 puntos.\nIntentalo de nuevo…
- Dibuja un patrón de desbloqueo:
- Dibuja el patrón de desbloqueo:
- Patrón guardado!
- Dibujar de nuevo para confirmar:
- Levanta el dedo cuando termines
- Lo siento, intentalo de nuevo
- Nuevo patrón de desbloqueo:
-
-
- Conecta al menos %1$d punto.\nIntentalo de nuevo…
- Conecta al menos %1$d puntos.\nIntentalo de nuevo…
-
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values-land/layouts.xml b/source-android-studio/app/src/main/res/values-land/layouts.xml
deleted file mode 100644
index 05906a0..0000000
--- a/source-android-studio/app/src/main/res/values-land/layouts.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- @layout/alp_42447968_lock_pattern_activity_land
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values-v11/styles.xml b/source-android-studio/app/src/main/res/values-v11/styles.xml
deleted file mode 100644
index 0f59083..0000000
--- a/source-android-studio/app/src/main/res/values-v11/styles.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values-v14/styles.xml b/source-android-studio/app/src/main/res/values-v14/styles.xml
deleted file mode 100644
index b7e5c41..0000000
--- a/source-android-studio/app/src/main/res/values-v14/styles.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values-v21/styles.xml b/source-android-studio/app/src/main/res/values-v21/styles.xml
deleted file mode 100644
index 117dc6d..0000000
--- a/source-android-studio/app/src/main/res/values-v21/styles.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values-vi/strings.xml b/source-android-studio/app/src/main/res/values-vi/strings.xml
deleted file mode 100644
index b27b7c5..0000000
--- a/source-android-studio/app/src/main/res/values-vi/strings.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
-
- Xác nhận
- Tiếp tục
- Quên rồi?
- Thử lại
- Đang tải…
- Đã thêm điểm
- Đã xóa mẫu khóa
- Hoàn thành mẫu khóa
- Bắt đầu mẫu khóa
- Kết nối ít nhứt 4 điểm.\nHãy thử lại…
- Vẽ mẫu khóa:
- Vẽ mẫu khóa để truy cập:
- Mẫu khóa đã được nhớ!
- Vẽ lại mẫu khóa để xác nhận:
- Thả ngón tay khi xong
- Xin lỗi, hãy thử lại
- Mẫu khóa mới của bạn:
-
-
- Kết nối ít nhứt %1$d điểm.\nHãy thử lại…
-
-
-
diff --git a/source-android-studio/app/src/main/res/values/colors.xml b/source-android-studio/app/src/main/res/values/colors.xml
deleted file mode 100644
index a93a408..0000000
--- a/source-android-studio/app/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
-
-
-
-
- #ffffffff
- #ffffffff
- #fff4511e
- #ff37474f
- #ff009688
- #fff4511e
- #cc515151
-
-
-
- #ff303030
- #ffeeeeee
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values/dimens.xml b/source-android-studio/app/src/main/res/values/dimens.xml
deleted file mode 100644
index 075ebbc..0000000
--- a/source-android-studio/app/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
- 350dp
- 1dp
-
-
-
- 3dp
- 12dp
- 28dp
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values/drawables.xml b/source-android-studio/app/src/main/res/values/drawables.xml
deleted file mode 100644
index 75702c6..0000000
--- a/source-android-studio/app/src/main/res/values/drawables.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values/preferences.xml b/source-android-studio/app/src/main/res/values/preferences.xml
deleted file mode 100644
index a8e6743..0000000
--- a/source-android-studio/app/src/main/res/values/preferences.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
- alp.pkey.sys.pattern
- alp.pkey.sys.auto_save_pattern
- alp.pkey.sys.encrypter_class
- alp.pkey.display.stealth_mode
- alp.pkey.display.min_wired_dots
- alp.pkey.display.max_retries
- alp.pkey.display.captcha_wired_dots
-
- false
- false
-
- 4
- 5
- 4
-
-
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values/strings.xml b/source-android-studio/app/src/main/res/values/strings.xml
deleted file mode 120000
index 3611ed1..0000000
--- a/source-android-studio/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1 +0,0 @@
-../values-en/strings.xml
\ No newline at end of file
diff --git a/source-android-studio/app/src/main/res/values/styles.xml b/source-android-studio/app/src/main/res/values/styles.xml
deleted file mode 100644
index aa3d9e4..0000000
--- a/source-android-studio/app/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,157 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @null
- @null
-
-
-
-
-
-
\ No newline at end of file
diff --git a/source-android-studio/build.gradle b/source-android-studio/build.gradle
deleted file mode 100644
index 6356aab..0000000
--- a/source-android-studio/build.gradle
+++ /dev/null
@@ -1,19 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
- repositories {
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:1.0.0'
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
-}
-
-allprojects {
- repositories {
- jcenter()
- }
-}
diff --git a/source-android-studio/gradle.properties b/source-android-studio/gradle.properties
deleted file mode 100644
index 1d3591c..0000000
--- a/source-android-studio/gradle.properties
+++ /dev/null
@@ -1,18 +0,0 @@
-# Project-wide Gradle settings.
-
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
-# Default value: -Xmx10248m -XX:MaxPermSize=256m
-# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
-
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
\ No newline at end of file
diff --git a/source-android-studio/gradlew b/source-android-studio/gradlew
deleted file mode 100644
index 91a7e26..0000000
--- a/source-android-studio/gradlew
+++ /dev/null
@@ -1,164 +0,0 @@
-#!/usr/bin/env bash
-
-##############################################################################
-##
-## Gradle start up script for UN*X
-##
-##############################################################################
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn ( ) {
- echo "$*"
-}
-
-die ( ) {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
-esac
-
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=$((i+1))
- done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
-fi
-
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
-}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
-
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/source-android-studio/gradlew.bat b/source-android-studio/gradlew.bat
deleted file mode 100644
index aec9973..0000000
--- a/source-android-studio/gradlew.bat
+++ /dev/null
@@ -1,90 +0,0 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/source-android-studio/settings.gradle b/source-android-studio/settings.gradle
deleted file mode 100644
index e7b4def..0000000
--- a/source-android-studio/settings.gradle
+++ /dev/null
@@ -1 +0,0 @@
-include ':app'
diff --git a/source-android-studio/source-android-studio.iml b/source-android-studio/source-android-studio.iml
deleted file mode 100644
index 2a02201..0000000
--- a/source-android-studio/source-android-studio.iml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-