aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-02-20 23:17:57 +0100
committerDominik Schürmann <dominik@dominikschuermann.de>2014-02-20 23:17:57 +0100
commita02d07b57cd99e6ac4edc427ceb83a5fad59fcf3 (patch)
treed2fe6ee38e08255b8e0f21fb8459191cdfa41623
parentaba0a3d0b1041bba012118852733da22c5924082 (diff)
parent15757a2a326f6af73361e193d80a4c4a91e64702 (diff)
downloadopen-keychain-a02d07b57cd99e6ac4edc427ceb83a5fad59fcf3.tar.gz
open-keychain-a02d07b57cd99e6ac4edc427ceb83a5fad59fcf3.tar.bz2
open-keychain-a02d07b57cd99e6ac4edc427ceb83a5fad59fcf3.zip
Merge pull request #282 from danielhass/master
Replaced Toasts with AppMsg library
-rw-r--r--OpenPGP-Keychain/build.gradle1
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java10
-rw-r--r--OpenPGP-Keychain/src/main/res/raw/help_about.html3
-rw-r--r--README.md3
-rw-r--r--libraries/Android-AppMsg/.gitignore36
-rw-r--r--libraries/Android-AppMsg/LICENSE.txt202
-rw-r--r--libraries/Android-AppMsg/README.md117
-rw-r--r--libraries/Android-AppMsg/library/AndroidManifest.xml12
-rw-r--r--libraries/Android-AppMsg/library/build.gradle22
-rw-r--r--libraries/Android-AppMsg/library/pom.xml71
-rw-r--r--libraries/Android-AppMsg/library/project.properties15
-rw-r--r--libraries/Android-AppMsg/library/res/layout/app_msg.xml20
-rw-r--r--libraries/Android-AppMsg/library/res/values/colors.xml8
-rw-r--r--libraries/Android-AppMsg/library/src/com/devspark/appmsg/AppMsg.java587
-rw-r--r--libraries/Android-AppMsg/library/src/com/devspark/appmsg/MsgManager.java340
-rw-r--r--settings.gradle1
16 files changed, 1442 insertions, 6 deletions
diff --git a/OpenPGP-Keychain/build.gradle b/OpenPGP-Keychain/build.gradle
index 28e8c37b1..1454b80e7 100644
--- a/OpenPGP-Keychain/build.gradle
+++ b/OpenPGP-Keychain/build.gradle
@@ -13,6 +13,7 @@ dependencies {
compile project(':libraries:spongycastle:pg')
compile project(':libraries:spongycastle:pkix')
compile project(':libraries:spongycastle:prov')
+ compile project(':libraries:Android-AppMsg:library')
}
android {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
index 1864e0d9d..a5027ac1c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -47,9 +47,9 @@ import android.support.v7.app.ActionBar;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
-import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton;
+import com.devspark.appmsg.AppMsg;
public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNavigationListener {
public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY";
@@ -282,8 +282,8 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
Log.d(Constants.TAG, "fingerprint: " + fingerprint);
if (fingerprint.length() < 16) {
- Toast.makeText(this, R.string.import_qr_code_too_short_fingerprint,
- Toast.LENGTH_LONG).show();
+ AppMsg.makeText(this, R.string.import_qr_code_too_short_fingerprint,
+ AppMsg.STYLE_ALERT).show();
return;
}
@@ -392,7 +392,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
} else {
toastMessage = getString(R.string.no_keys_added_or_updated);
}
- Toast.makeText(ImportKeysActivity.this, toastMessage, Toast.LENGTH_SHORT)
+ AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO)
.show();
if (bad > 0) {
AlertDialog.Builder alert = new AlertDialog.Builder(
@@ -474,7 +474,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
// start service with intent
startService(intent);
} else {
- Toast.makeText(this, R.string.error_nothing_import, Toast.LENGTH_LONG).show();
+ AppMsg.makeText(this, R.string.error_nothing_import, AppMsg.STYLE_ALERT).show();
}
}
diff --git a/OpenPGP-Keychain/src/main/res/raw/help_about.html b/OpenPGP-Keychain/src/main/res/raw/help_about.html
index 85130965c..882049c49 100644
--- a/OpenPGP-Keychain/src/main/res/raw/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw/help_about.html
@@ -34,8 +34,9 @@ And don't add newlines before or after p tags because of transifex -->
<li><a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
<li><a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
<li><a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
+<li><a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/README.md b/README.md
index 29a8d35ff..3a8c81b74 100644
--- a/README.md
+++ b/README.md
@@ -240,6 +240,9 @@ Some parts (older parts and some libraries are Apache License v2, MIT X11 Licens
https://github.com/Bearded-Hen/Android-Bootstrap
MIT License
+* Android AppMsg
+ https://github.com/johnkil/Android-AppMsg
+ Apache License v2
### Images
* icon.svg
diff --git a/libraries/Android-AppMsg/.gitignore b/libraries/Android-AppMsg/.gitignore
new file mode 100644
index 000000000..bdbc634c1
--- /dev/null
+++ b/libraries/Android-AppMsg/.gitignore
@@ -0,0 +1,36 @@
+#Android generated
+bin
+gen
+
+#Eclipse
+.project
+.classpath
+.settings
+
+#IntelliJ IDEA
+.idea
+*.iml
+*.ipr
+*.iws
+out
+
+#Maven
+target
+release.properties
+pom.xml.*
+
+#Ant
+build.xml
+local.properties
+proguard.cfg
+proguard-project.txt
+
+#Gradle
+.gradle
+build
+
+#OSX
+.DS_Store
+
+#Personal Files
+signing.properties
diff --git a/libraries/Android-AppMsg/LICENSE.txt b/libraries/Android-AppMsg/LICENSE.txt
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/libraries/Android-AppMsg/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ 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/libraries/Android-AppMsg/README.md b/libraries/Android-AppMsg/README.md
new file mode 100644
index 000000000..7f8006998
--- /dev/null
+++ b/libraries/Android-AppMsg/README.md
@@ -0,0 +1,117 @@
+Android AppMsg (Crouton) Library
+================================
+
+Implementation of in-layout notifications. Based on [Toast](http://developer.android.com/reference/android/widget/Toast.html) notifications and article [The making of Prixing #4: in-layout notifications](http://android.cyrilmottier.com/?p=773) by [Cyril Mottier](http://www.cyrilmottier.com/).
+
+
+Description
+-----------
+
+Toast is far from being perfect and I am not entirely satisfied with it.
+Toast can be un-accurate in some cases. Indeed, Toast has one major drawback: it completely breaks contexts.
+This issue can be reproduced effortless. Let’s say a user is currently in an app firing a Toast and wants to switch to another application using the dedicated “multitask” button.
+The Toast will remain on screen even if the brought-to-front application has nothing do to with the previously shown app as described on the following figure:
+![Example Image][1]
+
+As you can easily notice, the problem with Toasts is they are persistent.
+Once a Toast has been fired, it is displayed on top of any screen and remains visible for the duration specified at its creation.
+
+In order to bypass the Toast persistence problem and ensure information is displayed in the correct context, we decided to create a new notification system:
+Activity-bound notifications. This is what it looks like in the current version of Prixing:
+![Example Image][2]
+
+Crouton overcomes the main issue of having a Toast being shown while the menu is open.
+It sticks to the current screen sliding with it and leaving the menu completely free of any information that would have not been related to it.
+
+<b>Copyright (C) by Cyril Mottier</b>
+
+Sample
+------
+
+A sample application is available on Google Play:
+
+<a href="http://play.google.com/store/apps/details?id=com.devspark.appmsg.sample">
+ <img alt="Get it on Google Play"
+ src="http://www.android.com/images/brand/get_it_on_play_logo_small.png" />
+</a>
+
+![Example Image][3]
+
+The source code is available in this repository.
+
+Compatibility
+-------------
+
+This library is compatible from API 4 (Android 1.6).
+
+Installation
+------------
+
+The sample project requires:
+
+* The library project
+* [ActionBarSherlock](https://github.com/JakeWharton/ActionBarSherlock)
+
+Usage
+-----
+
+Android AppMsg is presented as an [Android library project](http://developer.android.com/guide/developing/projects/projects-eclipse.html).
+You can include this project by [referencing it as a library project](http://developer.android.com/guide/developing/projects/projects-eclipse.html#ReferencingLibraryProject) in Eclipse or ant.
+
+To display the item you need the following code:
+
+* Show AppMsg:
+
+``` java
+AppMsg.makeText(/*Activity*/, /*CharSequence*/, /*AppMsg.Style*/).show();
+```
+
+Gradle
+------
+
+Android-AppMsg Library is now pushed to Maven Central as a AAR, so you just need to add the following dependency to your build.gradle.
+
+``` xml
+dependencies {
+ compile 'com.github.johnkil.android-appmsg:appmsg:1.2.0'
+}
+```
+
+Example Gradle project using Android-AppMsg:
+
+* [Android-AppMsg-Gradle-Sample](https://github.com/johnkil/Android-AppMsg-Gradle-Sample)
+
+
+Contribution
+------------
+
+Please fork [dev](https://github.com/johnkil/Android-AppMsg/tree/dev) repository and contribute back using [pull requests](https://github.com/johnkil/Android-AppMsg/pulls).
+
+Contributors are recommended to follow the Android [Code Style Guidelines](http://source.android.com/source/code-style.html).
+
+Any contributions, large or small, major features, bug fixes, additional language translations, unit/integration tests are welcomed and appreciated but will be thoroughly reviewed and discussed.
+
+Developed By
+------------
+* Evgeny Shishkin - <johnkil78@gmail.com>
+
+License
+-------
+
+ Copyright 2012 Evgeny Shishkin
+
+ 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.
+
+[1]: http://cyrilmottier.com/media/2012/07/the-making-of-prixing-4-activity-tied-notifications/toast_user_flow_fail.png
+[2]: http://cyrilmottier.com/media/2012/07/the-making-of-prixing-4-activity-tied-notifications/in_layout_notification.png
+[3]: http://i46.tinypic.com/21kywit.png
diff --git a/libraries/Android-AppMsg/library/AndroidManifest.xml b/libraries/Android-AppMsg/library/AndroidManifest.xml
new file mode 100644
index 000000000..c03f66559
--- /dev/null
+++ b/libraries/Android-AppMsg/library/AndroidManifest.xml
@@ -0,0 +1,12 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.devspark.appmsg"
+ android:versionCode="5"
+ android:versionName="1.2.0">
+
+ <uses-sdk
+ android:minSdkVersion="4"
+ android:targetSdkVersion="19"/>
+
+ <application/>
+
+</manifest> \ No newline at end of file
diff --git a/libraries/Android-AppMsg/library/build.gradle b/libraries/Android-AppMsg/library/build.gradle
new file mode 100644
index 000000000..934cf1cb1
--- /dev/null
+++ b/libraries/Android-AppMsg/library/build.gradle
@@ -0,0 +1,22 @@
+apply plugin: 'android-library'
+
+android {
+ compileSdkVersion 19
+ buildToolsVersion '19.0.1'
+
+ defaultConfig {
+ minSdkVersion 4
+ }
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src']
+ res.srcDirs = ['res']
+ }
+ }
+}
+
+if (project.hasProperty('nexusUsername')) {
+ // Used to push in maven
+ apply from: '../maven_push.gradle'
+} \ No newline at end of file
diff --git a/libraries/Android-AppMsg/library/pom.xml b/libraries/Android-AppMsg/library/pom.xml
new file mode 100644
index 000000000..149557370
--- /dev/null
+++ b/libraries/Android-AppMsg/library/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>com.devspark</groupId>
+ <artifactId>appmsg</artifactId>
+ <version>1.0.1</version>
+ <packaging>apklib</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.android</groupId>
+ <artifactId>android</artifactId>
+ <version>4.1.1.4</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <version>2.7.1</version>
+ <configuration>
+ <linkXref>true</linkXref>
+ <sourceEncoding>utf-8</sourceEncoding>
+ <minimumTokens>100</minimumTokens>
+ <targetJdk>1.6</targetJdk>
+ <excludes>
+ <exclude>**/*Bean.java</exclude>
+ <exclude>**/generated/*.java</exclude>
+ </excludes>
+ <excludeRoots>
+ <excludeRoot>target/generated-sources/stubs</excludeRoot>
+ </excludeRoots>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>com.jayway.maven.plugins.android.generation2</groupId>
+ <artifactId>android-maven-plugin</artifactId>
+ <version>3.6.0</version>
+ <configuration>
+ <androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>
+ <assetsDirectory>${project.basedir}/assets</assetsDirectory>
+ <resourceDirectory>${project.basedir}/res</resourceDirectory>
+ <nativeLibrariesDirectory>${project.basedir}/src/main/native</nativeLibrariesDirectory>
+ <sdk>
+ <platform>16</platform>
+ </sdk>
+ <undeployBeforeDeploy>true</undeployBeforeDeploy>
+ </configuration>
+ <extensions>true</extensions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/libraries/Android-AppMsg/library/project.properties b/libraries/Android-AppMsg/library/project.properties
new file mode 100644
index 000000000..91d2b0246
--- /dev/null
+++ b/libraries/Android-AppMsg/library/project.properties
@@ -0,0 +1,15 @@
+# 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-19
+android.library=true
diff --git a/libraries/Android-AppMsg/library/res/layout/app_msg.xml b/libraries/Android-AppMsg/library/res/layout/app_msg.xml
new file mode 100644
index 000000000..235fe47b9
--- /dev/null
+++ b/libraries/Android-AppMsg/library/res/layout/app_msg.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:minHeight="48dp"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@android:id/message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:padding="8dp"
+ android:textColor="?android:textColorPrimaryInverse"
+ android:textIsSelectable="false"
+ android:textSize="14sp"
+ android:textStyle="bold" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/libraries/Android-AppMsg/library/res/values/colors.xml b/libraries/Android-AppMsg/library/res/values/colors.xml
new file mode 100644
index 000000000..2bfd9ecb4
--- /dev/null
+++ b/libraries/Android-AppMsg/library/res/values/colors.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <color name="alert">#CC0000</color>
+ <color name="confirm">#FF8800</color>
+ <color name="info">#669900</color>
+
+</resources> \ No newline at end of file
diff --git a/libraries/Android-AppMsg/library/src/com/devspark/appmsg/AppMsg.java b/libraries/Android-AppMsg/library/src/com/devspark/appmsg/AppMsg.java
new file mode 100644
index 000000000..e86273762
--- /dev/null
+++ b/libraries/Android-AppMsg/library/src/com/devspark/appmsg/AppMsg.java
@@ -0,0 +1,587 @@
+/*
+ * Copyright 2012 Evgeny Shishkin
+ *
+ * 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.devspark.appmsg;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+/**
+ * In-layout notifications. Based on {@link android.widget.Toast} notifications
+ * and article by Cyril Mottier (http://android.cyrilmottier.com/?p=773).
+ *
+ * @author e.shishkin
+ */
+public class AppMsg {
+
+ /**
+ * Show the view or text notification for a short period of time. This time
+ * could be user-definable. This is the default.
+ *
+ * @see #setDuration
+ */
+ public static final int LENGTH_SHORT = 3000;
+
+ /**
+ * Show the view or text notification for a long period of time. This time
+ * could be user-definable.
+ *
+ * @see #setDuration
+ */
+ public static final int LENGTH_LONG = 5000;
+
+ /**
+ * <p>Show the view or text notification for an undefined amount of time
+ * -Usually until an invocation of {@link #cancel()}, {@link #cancelAll(android.app.Activity)},
+ * {@link #cancelAll()} or {@link android.app.Activity#onDestroy()}-,
+ * stacking on top of any other {@link com.devspark.appmsg.AppMsg} with this duration.</p>
+ *
+ * <p><b>Note</b>: You are responsible
+ * for calling {@link #cancel()} on such {@link com.devspark.appmsg.AppMsg}.</p>
+ *
+ * @see #setDuration
+ */
+ public static final int LENGTH_STICKY = -1;
+
+ /**
+ * Lowest priority, messages with this priority will be showed after all messages with priority
+ * {@link #PRIORITY_HIGH} and {@link #PRIORITY_NORMAL} have been shown.
+ *
+ * @see #setPriority(int)
+ */
+ public static final int PRIORITY_LOW = Integer.MIN_VALUE;
+ /**
+ * Normal priority, messages with this priority will be showed after all messages with priority
+ * {@link #PRIORITY_HIGH} but before {@link #PRIORITY_LOW} have been shown.
+ *
+ * @see #setPriority(int)
+ */
+ public static final int PRIORITY_NORMAL = 0;
+ /**
+ * Highest priority, messages with this priority will be showed before any other message.
+ *
+ * @see #setPriority(int)
+ */
+ public static final int PRIORITY_HIGH = Integer.MAX_VALUE;
+
+ /**
+ * Show the text notification for a long period of time with a negative style.
+ */
+ public static final Style STYLE_ALERT = new Style(LENGTH_LONG, R.color.alert);
+
+ /**
+ * Show the text notification for a short period of time with a positive style.
+ */
+ public static final Style STYLE_CONFIRM = new Style(LENGTH_SHORT, R.color.confirm);
+
+ /**
+ * Show the text notification for a short period of time with a neutral style.
+ */
+ public static final Style STYLE_INFO = new Style(LENGTH_SHORT, R.color.info);
+
+ private final Activity mActivity;
+ private int mDuration = LENGTH_SHORT;
+ private View mView;
+ private ViewGroup mParent;
+ private LayoutParams mLayoutParams;
+ private boolean mFloating;
+ Animation mInAnimation, mOutAnimation;
+ int mPriority = PRIORITY_NORMAL;
+
+ /**
+ * Construct an empty AppMsg object. You must call {@link #setView} before
+ * you can call {@link #show}.
+ *
+ * @param activity {@link android.app.Activity} to use.
+ */
+ public AppMsg(Activity activity) {
+ mActivity = activity;
+ }
+
+ /**
+ * Make a {@link AppMsg} that just contains a text view.
+ *
+ * @param context The context to use. Usually your
+ * {@link android.app.Activity} object.
+ * @param text The text to show. Can be formatted text.
+ * @param style The style with a background and a duration.
+ */
+ public static AppMsg makeText(Activity context, CharSequence text, Style style) {
+ return makeText(context, text, style, R.layout.app_msg);
+ }
+
+ /**
+ * @author mengguoqiang 扩展支持设置字体大小
+ * Make a {@link AppMsg} that just contains a text view.
+ *
+ * @param context The context to use. Usually your
+ * {@link android.app.Activity} object.
+ * @param text The text to show. Can be formatted text.
+ * @param style The style with a background and a duration.
+ */
+ public static AppMsg makeText(Activity context, CharSequence text, Style style, float textSize) {
+ return makeText(context, text, style, R.layout.app_msg, textSize);
+ }
+
+ /**
+ * Make a {@link AppMsg} with a custom layout. The layout must have a {@link TextView} com id {@link android.R.id.message}
+ *
+ * @param context The context to use. Usually your
+ * {@link android.app.Activity} object.
+ * @param text The text to show. Can be formatted text.
+ * @param style The style with a background and a duration.
+ */
+ public static AppMsg makeText(Activity context, CharSequence text, Style style, int layoutId) {
+ LayoutInflater inflate = (LayoutInflater)
+ context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View v = inflate.inflate(layoutId, null);
+
+ return makeText(context, text, style, v, true);
+ }
+
+ /**
+ * @author mengguoqiang 扩展支持字体大小
+ * Make a {@link AppMsg} with a custom layout. The layout must have a {@link TextView} com id {@link android.R.id.message}
+ *
+ * @param context The context to use. Usually your
+ * {@link android.app.Activity} object.
+ * @param text The text to show. Can be formatted text.
+ * @param style The style with a background and a duration.
+ */
+ public static AppMsg makeText(Activity context, CharSequence text, Style style, int layoutId, float textSize) {
+ LayoutInflater inflate = (LayoutInflater)
+ context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View v = inflate.inflate(layoutId, null);
+
+ return makeText(context, text, style, v, true, textSize);
+ }
+
+ /**
+ * Make a non-floating {@link AppMsg} with a custom view presented inside the layout.
+ * It can be used to create non-floating notifications if floating is false.
+ *
+ * @param context The context to use. Usually your
+ * {@link android.app.Activity} object.
+ * @param customView
+ * View to be used.
+ * @param text The text to show. Can be formatted text.
+ * @param style The style with a background and a duration.
+ */
+ public static AppMsg makeText(Activity context, CharSequence text, Style style, View customView) {
+ return makeText(context, text, style, customView, false);
+ }
+
+ /**
+ * Make a {@link AppMsg} with a custom view. It can be used to create non-floating notifications if floating is false.
+ *
+ * @param context The context to use. Usually your
+ * {@link android.app.Activity} object.
+ * @param view
+ * View to be used.
+ * @param text The text to show. Can be formatted text.
+ * @param style The style with a background and a duration.
+ * @param floating true if it'll float.
+ */
+ private static AppMsg makeText(Activity context, CharSequence text, Style style, View view, boolean floating) {
+ return makeText(context, text, style, view, floating, 0);
+ }
+
+ /**
+ *
+ * @author mengguoqiang 扩展支持设置字体大小
+ * Make a {@link AppMsg} with a custom view. It can be used to create non-floating notifications if floating is false.
+ *
+ * @param context The context to use. Usually your
+ * {@link android.app.Activity} object.
+ * @param view
+ * View to be used.
+ * @param text The text to show. Can be formatted text.
+ * @param style The style with a background and a duration.
+ * @param floating true if it'll float.
+ */
+ private static AppMsg makeText(Activity context, CharSequence text, Style style, View view, boolean floating, float textSize) {
+ AppMsg result = new AppMsg(context);
+
+ view.setBackgroundResource(style.background);
+
+ TextView tv = (TextView) view.findViewById(android.R.id.message);
+ if(textSize > 0) tv.setTextSize(textSize);
+ tv.setText(text);
+
+ result.mView = view;
+ result.mDuration = style.duration;
+ result.mFloating = floating;
+
+ return result;
+ }
+
+ /**
+ * Make a {@link AppMsg} with a custom view. It can be used to create non-floating notifications if floating is false.
+ *
+ * @param context The context to use. Usually your
+ * {@link android.app.Activity} object.
+ * @param resId The resource id of the string resource to use. Can be
+ * formatted text.
+ * @param style The style with a background and a duration.
+ * @param floating true if it'll float.
+ */
+ public static AppMsg makeText(Activity context, int resId, Style style, View customView, boolean floating) {
+ return makeText(context, context.getResources().getText(resId), style, customView, floating);
+ }
+
+ /**
+ * Make a {@link AppMsg} that just contains a text view with the text from a
+ * resource.
+ *
+ * @param context The context to use. Usually your
+ * {@link android.app.Activity} object.
+ * @param resId The resource id of the string resource to use. Can be
+ * formatted text.
+ * @param style The style with a background and a duration.
+ * @throws Resources.NotFoundException if the resource can't be found.
+ */
+ public static AppMsg makeText(Activity context, int resId, Style style)
+ throws Resources.NotFoundException {
+ return makeText(context, context.getResources().getText(resId), style);
+ }
+
+ /**
+ * Make a {@link AppMsg} with a custom layout using the text from a
+ * resource. The layout must have a {@link TextView} com id {@link android.R.id.message}
+ *
+ * @param context The context to use. Usually your
+ * {@link android.app.Activity} object.
+ * @param resId The resource id of the string resource to use. Can be
+ * formatted text.
+ * @param style The style with a background and a duration.
+ * @throws Resources.NotFoundException if the resource can't be found.
+ */
+ public static AppMsg makeText(Activity context, int resId, Style style, int layoutId)
+ throws Resources.NotFoundException {
+ return makeText(context, context.getResources().getText(resId), style, layoutId);
+ }
+
+ /**
+ * Show the view for the specified duration.
+ */
+ public void show() {
+ MsgManager manager = MsgManager.obtain(mActivity);
+ manager.add(this);
+ }
+
+ /**
+ * @return <code>true</code> if the {@link AppMsg} is being displayed, else <code>false</code>.
+ */
+ public boolean isShowing() {
+ if (mFloating) {
+ return mView != null && mView.getParent() != null;
+ } else {
+ return mView.getVisibility() == View.VISIBLE;
+ }
+ }
+
+ /**
+ * Close the view if it's showing, or don't show it if it isn't showing yet.
+ * You do not normally have to call this. Normally view will disappear on its own
+ * after the appropriate duration.
+ */
+ public void cancel() {
+ MsgManager.obtain(mActivity).clearMsg(this);
+
+ }
+
+ /**
+ * Cancels all queued {@link AppMsg}s, in all Activities. If there is a {@link AppMsg}
+ * displayed currently, it will be the last one displayed.
+ */
+ public static void cancelAll() {
+ MsgManager.clearAll();
+ }
+
+ /**
+ * Cancels all queued {@link AppMsg}s, in given {@link android.app.Activity}.
+ * If there is a {@link AppMsg} displayed currently, it will be the last one displayed.
+ * @param activity
+ */
+ public static void cancelAll(Activity activity) {
+ MsgManager.release(activity);
+ }
+
+ /**
+ * Return the activity.
+ */
+ public Activity getActivity() {
+ return mActivity;
+ }
+
+ /**
+ * Set the view to show.
+ *
+ * @see #getView
+ */
+ public void setView(View view) {
+ mView = view;
+ }
+
+ /**
+ * Return the view.
+ *
+ * @see #setView
+ */
+ public View getView() {
+ return mView;
+ }
+
+ /**
+ * Set how long to show the view for.
+ *
+ * @see #LENGTH_SHORT
+ * @see #LENGTH_LONG
+ */
+ public void setDuration(int duration) {
+ mDuration = duration;
+ }
+
+ /**
+ * Return the duration.
+ *
+ * @see #setDuration
+ */
+ public int getDuration() {
+ return mDuration;
+ }
+
+ /**
+ * Update the text in a AppMsg that was previously created using one of the makeText() methods.
+ *
+ * @param resId The new text for the AppMsg.
+ */
+ public void setText(int resId) {
+ setText(mActivity.getText(resId));
+ }
+
+ /**
+ * Update the text in a AppMsg that was previously created using one of the makeText() methods.
+ *
+ * @param s The new text for the AppMsg.
+ */
+ public void setText(CharSequence s) {
+ if (mView == null) {
+ throw new RuntimeException("This AppMsg was not created with AppMsg.makeText()");
+ }
+ TextView tv = (TextView) mView.findViewById(android.R.id.message);
+ if (tv == null) {
+ throw new RuntimeException("This AppMsg was not created with AppMsg.makeText()");
+ }
+ tv.setText(s);
+ }
+
+ /**
+ * Gets the crouton's layout parameters, constructing a default if necessary.
+ *
+ * @return the layout parameters
+ */
+ public LayoutParams getLayoutParams() {
+ if (mLayoutParams == null) {
+ mLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ }
+ return mLayoutParams;
+ }
+
+ /**
+ * Sets the layout parameters which will be used to display the crouton.
+ *
+ * @param layoutParams The layout parameters to use.
+ * @return <code>this</code>, for chaining.
+ */
+ public AppMsg setLayoutParams(LayoutParams layoutParams) {
+ mLayoutParams = layoutParams;
+ return this;
+ }
+
+ /**
+ * Constructs and sets the layout parameters to have some gravity.
+ *
+ * @param gravity the gravity of the Crouton
+ * @return <code>this</code>, for chaining.
+ * @see android.view.Gravity
+ */
+ public AppMsg setLayoutGravity(int gravity) {
+ mLayoutParams = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, gravity);
+ return this;
+ }
+
+ /**
+ * Return the value of floating.
+ *
+ * @see #setFloating(boolean)
+ */
+ public boolean isFloating() {
+ return mFloating;
+ }
+
+ /**
+ * Sets the value of floating.
+ *
+ * @param mFloating
+ */
+ public void setFloating(boolean mFloating) {
+ this.mFloating = mFloating;
+ }
+
+ /**
+ * Sets the Animations to be used when displaying/removing the Crouton.
+ * @param inAnimation the Animation resource ID to be used when displaying.
+ * @param outAnimation the Animation resource ID to be used when removing.
+ */
+ public AppMsg setAnimation(int inAnimation, int outAnimation) {
+ return setAnimation(AnimationUtils.loadAnimation(mActivity, inAnimation),
+ AnimationUtils.loadAnimation(mActivity, outAnimation));
+ }
+
+ /**
+ * Sets the Animations to be used when displaying/removing the Crouton.
+ * @param inAnimation the Animation to be used when displaying.
+ * @param outAnimation the Animation to be used when removing.
+ */
+ public AppMsg setAnimation(Animation inAnimation, Animation outAnimation) {
+ mInAnimation = inAnimation;
+ mOutAnimation = outAnimation;
+ return this;
+ }
+
+ /**
+ * @return
+ * Current priority
+ *
+ * @see #PRIORITY_HIGH
+ * @see #PRIORITY_NORMAL
+ * @see #PRIORITY_LOW
+ */
+ public int getPriority() {
+ return mPriority;
+ }
+
+ /**
+ * <p>Set priority for this message</p>
+ * <p><b>Note</b>: This only affects the order in which the messages get shown,
+ * not the stacking order of the views.</p>
+ *
+ * <p>Example: In the queue there are 3 messages [A, B, C],
+ * all of them with priority {@link #PRIORITY_NORMAL}, currently message A is being shown
+ * so we add a new message D with priority {@link #PRIORITY_HIGH}, after A goes away, given that
+ * D has a higher priority than B an the reset, D will be shown, then once that D is gone,
+ * B will be shown, and then finally C.</p>
+ *
+ * @param priority
+ * A value indicating priority, although you can use any integer value, usage of already
+ * defined is highly encouraged.
+ *
+ * @see #PRIORITY_HIGH
+ * @see #PRIORITY_NORMAL
+ * @see #PRIORITY_LOW
+ */
+ public void setPriority(int priority) {
+ mPriority = priority;
+ }
+
+ /**
+ * @return
+ * Provided parent to add {@link #getView()} to using {@link #getLayoutParams()}.
+ */
+ public ViewGroup getParent() {
+ return mParent;
+ }
+
+ /**
+ * Provide a different parent than Activity decor view
+ * @param parent
+ * Provided parent to add {@link #getView()} to using {@link #getLayoutParams()}.
+ *
+ */
+ public void setParent(ViewGroup parent) {
+ mParent = parent;
+ }
+
+ /**
+ * Provide a different parent than Activity decor view
+ *
+ * @param parentId
+ * Provided parent id to add {@link #getView()} to using {@link #getLayoutParams()}.
+ *
+ */
+ public void setParent(int parentId) {
+ setParent((ViewGroup) mActivity.findViewById(parentId));
+ }
+
+ /**
+ * The style for a {@link AppMsg}.
+ *
+ * @author e.shishkin
+ */
+ public static class Style {
+
+ private final int duration;
+ private final int background;
+
+ /**
+ * Construct an {@link AppMsg.Style} object.
+ *
+ * @param duration How long to display the message. Either
+ * {@link #LENGTH_SHORT} or {@link #LENGTH_LONG}
+ * @param resId resource for AppMsg background
+ */
+ public Style(int duration, int resId) {
+ this.duration = duration;
+ this.background = resId;
+ }
+
+ /**
+ * Return the duration in milliseconds.
+ */
+ public int getDuration() {
+ return duration;
+ }
+
+ /**
+ * Return the resource id of background.
+ */
+ public int getBackground() {
+ return background;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof AppMsg.Style)) {
+ return false;
+ }
+ Style style = (Style) o;
+ return style.duration == duration
+ && style.background == background;
+ }
+
+ }
+
+}
diff --git a/libraries/Android-AppMsg/library/src/com/devspark/appmsg/MsgManager.java b/libraries/Android-AppMsg/library/src/com/devspark/appmsg/MsgManager.java
new file mode 100644
index 000000000..962648566
--- /dev/null
+++ b/libraries/Android-AppMsg/library/src/com/devspark/appmsg/MsgManager.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2012 Evgeny Shishkin
+ *
+ * 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.devspark.appmsg;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.Application;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.PriorityQueue;
+import java.util.Queue;
+import java.util.WeakHashMap;
+
+import static android.app.Application.ActivityLifecycleCallbacks;
+import static android.os.Build.VERSION.SDK_INT;
+import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+import static com.devspark.appmsg.AppMsg.LENGTH_STICKY;
+
+/**
+ * @author Evgeny Shishkin
+ */
+class MsgManager extends Handler implements Comparator<AppMsg> {
+
+ private static final int MESSAGE_DISPLAY = 0xc2007;
+ private static final int MESSAGE_ADD_VIEW = 0xc20074dd;
+ private static final int MESSAGE_REMOVE = 0xc2007de1;
+
+ private static WeakHashMap<Activity, MsgManager> sManagers;
+ private static ReleaseCallbacks sReleaseCallbacks;
+
+ private final Queue<AppMsg> msgQueue;
+ private final Queue<AppMsg> stickyQueue;
+
+ private MsgManager() {
+ msgQueue = new PriorityQueue<AppMsg>(1, this);
+ stickyQueue = new LinkedList<AppMsg>();
+ }
+
+ /**
+ * @return A {@link MsgManager} instance to be used for given {@link android.app.Activity}.
+ */
+ static synchronized MsgManager obtain(Activity activity) {
+ if (sManagers == null) {
+ sManagers = new WeakHashMap<Activity, MsgManager>(1);
+ }
+ MsgManager manager = sManagers.get(activity);
+ if (manager == null) {
+ manager = new MsgManager();
+ ensureReleaseOnDestroy(activity);
+ sManagers.put(activity, manager);
+ }
+
+ return manager;
+ }
+
+ static void ensureReleaseOnDestroy(Activity activity) {
+ if (SDK_INT < ICE_CREAM_SANDWICH) {
+ return;
+ }
+ if (sReleaseCallbacks == null) {
+ sReleaseCallbacks = new ReleaseCallbacksIcs();
+ }
+ sReleaseCallbacks.register(activity.getApplication());
+ }
+
+
+ static synchronized void release(Activity activity) {
+ if (sManagers != null) {
+ final MsgManager manager = sManagers.remove(activity);
+ if (manager != null) {
+ manager.clearAllMsg();
+ }
+ }
+ }
+
+ static synchronized void clearAll() {
+ if (sManagers != null) {
+ final Iterator<MsgManager> iterator = sManagers.values().iterator();
+ while (iterator.hasNext()) {
+ final MsgManager manager = iterator.next();
+ if (manager != null) {
+ manager.clearAllMsg();
+ }
+ iterator.remove();
+ }
+ sManagers.clear();
+ }
+ }
+
+ /**
+ * Inserts a {@link AppMsg} to be displayed.
+ *
+ * @param appMsg
+ */
+ void add(AppMsg appMsg) {
+ msgQueue.add(appMsg);
+ if (appMsg.mInAnimation == null) {
+ appMsg.mInAnimation = AnimationUtils.loadAnimation(appMsg.getActivity(),
+ android.R.anim.fade_in);
+ }
+ if (appMsg.mOutAnimation == null) {
+ appMsg.mOutAnimation = AnimationUtils.loadAnimation(appMsg.getActivity(),
+ android.R.anim.fade_out);
+ }
+ displayMsg();
+ }
+
+ /**
+ * Removes all {@link AppMsg} from the queue.
+ */
+ void clearMsg(AppMsg appMsg) {
+ if(msgQueue.contains(appMsg) || stickyQueue.contains(appMsg)){
+ // Avoid the message from being removed twice.
+ removeMessages(MESSAGE_DISPLAY, appMsg);
+ removeMessages(MESSAGE_ADD_VIEW, appMsg);
+ removeMessages(MESSAGE_REMOVE, appMsg);
+ msgQueue.remove(appMsg);
+ stickyQueue.remove(appMsg);
+ removeMsg(appMsg);
+ }
+ }
+
+ /**
+ * Removes all {@link AppMsg} from the queue.
+ */
+ void clearAllMsg() {
+ removeMessages(MESSAGE_DISPLAY);
+ removeMessages(MESSAGE_ADD_VIEW);
+ removeMessages(MESSAGE_REMOVE);
+ clearShowing();
+ msgQueue.clear();
+ stickyQueue.clear();
+ }
+
+ void clearShowing() {
+ final Collection<AppMsg> showing = new HashSet<AppMsg>();
+ obtainShowing(msgQueue, showing);
+ obtainShowing(stickyQueue, showing);
+ for (AppMsg msg : showing) {
+ clearMsg(msg);
+ }
+ }
+
+ static void obtainShowing(Collection<AppMsg> from, Collection<AppMsg> appendTo) {
+ for (AppMsg msg : from) {
+ if (msg.isShowing()) {
+ appendTo.add(msg);
+ }
+ }
+ }
+
+ /**
+ * Displays the next {@link AppMsg} within the queue.
+ */
+ private void displayMsg() {
+ if (msgQueue.isEmpty()) {
+ return;
+ }
+ // First peek whether the AppMsg is being displayed.
+ final AppMsg appMsg = msgQueue.peek();
+ final Message msg;
+ if (!appMsg.isShowing()) {
+ // Display the AppMsg
+ msg = obtainMessage(MESSAGE_ADD_VIEW);
+ msg.obj = appMsg;
+ sendMessage(msg);
+ } else if (appMsg.getDuration() != LENGTH_STICKY) {
+ msg = obtainMessage(MESSAGE_DISPLAY);
+ sendMessageDelayed(msg, appMsg.getDuration()
+ + appMsg.mInAnimation.getDuration() + appMsg.mOutAnimation.getDuration());
+ }
+ }
+
+ /**
+ * Removes the {@link AppMsg}'s view after it's display duration.
+ *
+ * @param appMsg The {@link AppMsg} added to a {@link ViewGroup} and should be removed.s
+ */
+ private void removeMsg(final AppMsg appMsg) {
+ clearMsg(appMsg);
+ final View view = appMsg.getView();
+ ViewGroup parent = ((ViewGroup) view.getParent());
+ if (parent != null) {
+ appMsg.mOutAnimation.setAnimationListener(new OutAnimationListener(appMsg));
+ view.clearAnimation();
+ view.startAnimation(appMsg.mOutAnimation);
+ }
+
+ Message msg = obtainMessage(MESSAGE_DISPLAY);
+ sendMessage(msg);
+ }
+
+ private void addMsgToView(AppMsg appMsg) {
+ View view = appMsg.getView();
+ if (view.getParent() == null) { // Not added yet
+ final ViewGroup targetParent = appMsg.getParent();
+ final ViewGroup.LayoutParams params = appMsg.getLayoutParams();
+ if (targetParent != null) {
+ targetParent.addView(view, params);
+ } else {
+ appMsg.getActivity().addContentView(view, params);
+ }
+ }
+ view.clearAnimation();
+ view.startAnimation(appMsg.mInAnimation);
+ if (view.getVisibility() != View.VISIBLE) {
+ view.setVisibility(View.VISIBLE);
+ }
+
+ final int duration = appMsg.getDuration();
+ if (duration != LENGTH_STICKY) {
+ final Message msg = obtainMessage(MESSAGE_REMOVE);
+ msg.obj = appMsg;
+ sendMessageDelayed(msg, duration);
+ } else { // We are sticky, we don't get removed just yet
+ stickyQueue.add(msgQueue.poll());
+ }
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ final AppMsg appMsg;
+ switch (msg.what) {
+ case MESSAGE_DISPLAY:
+ displayMsg();
+ break;
+ case MESSAGE_ADD_VIEW:
+ appMsg = (AppMsg) msg.obj;
+ addMsgToView(appMsg);
+ break;
+ case MESSAGE_REMOVE:
+ appMsg = (AppMsg) msg.obj;
+ removeMsg(appMsg);
+ break;
+ default:
+ super.handleMessage(msg);
+ break;
+ }
+ }
+
+ @Override
+ public int compare(AppMsg lhs, AppMsg rhs) {
+ return inverseCompareInt(lhs.mPriority, rhs.mPriority);
+ }
+
+ static int inverseCompareInt(int lhs, int rhs) {
+ return lhs < rhs ? 1 : (lhs == rhs ? 0 : -1);
+ }
+
+ private static class OutAnimationListener implements Animation.AnimationListener {
+
+ private final AppMsg appMsg;
+
+ private OutAnimationListener(AppMsg appMsg) {
+ this.appMsg = appMsg;
+ }
+
+ @Override
+ public void onAnimationStart(Animation animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ final View view = appMsg.getView();
+ if (appMsg.isFloating()) {
+ final ViewGroup parent = ((ViewGroup) view.getParent());
+ if (parent != null) {
+ parent.post(new Runnable() { // One does not simply removeView
+ @Override
+ public void run() {
+ parent.removeView(view);
+ }
+ });
+ }
+ } else {
+ view.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+
+ }
+ }
+
+ interface ReleaseCallbacks {
+ void register(Application application);
+ }
+
+ @TargetApi(ICE_CREAM_SANDWICH)
+ static class ReleaseCallbacksIcs implements ActivityLifecycleCallbacks, ReleaseCallbacks {
+ private WeakReference<Application> mLastApp;
+ public void register(Application app) {
+ if (mLastApp != null && mLastApp.get() == app) {
+ return; // Already registered with this app
+ } else {
+ mLastApp = new WeakReference<Application>(app);
+ }
+ app.registerActivityLifecycleCallbacks(this);
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ release(activity);
+ }
+ @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
+ @Override public void onActivityStarted(Activity activity) {}
+ @Override public void onActivityResumed(Activity activity) {}
+ @Override public void onActivityPaused(Activity activity) {}
+ @Override public void onActivityStopped(Activity activity) {}
+ @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
+ }
+} \ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 344278063..f123762aa 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -9,3 +9,4 @@ include ':libraries:spongycastle:core'
include ':libraries:spongycastle:pg'
include ':libraries:spongycastle:pkix'
include ':libraries:spongycastle:prov'
+include ':libraries:Android-AppMsg:library'