Use git submodules for libs, fix compilation, remove library sourcecode

This commit is contained in:
Dominik Schürmann 2014-04-16 21:49:29 +02:00
parent b0c65729a9
commit f7c243564f
4454 changed files with 68 additions and 866772 deletions

21
.gitmodules vendored Normal file
View File

@ -0,0 +1,21 @@
[submodule "extern/StickyListHeaders"]
path = extern/StickyListHeaders
url = https://github.com/open-keychain/StickyListHeaders.git
[submodule "extern/AndroidBootstrap"]
path = extern/AndroidBootstrap
url = https://github.com/open-keychain/Android-Bootstrap.git
[submodule "extern/zxing-android-integration"]
path = extern/zxing-android-integration
url = https://github.com/open-keychain/zxing-android-integration.git
[submodule "extern/zxing-qr-code"]
path = extern/zxing-qr-code
url = https://github.com/open-keychain/zxing-qr-code.git
[submodule "extern/AppMsg"]
path = extern/AppMsg
url = https://github.com/open-keychain/Android-AppMsg.git
[submodule "extern/spongycastle"]
path = extern/spongycastle
url = https://github.com/open-keychain/spongycastle.git
[submodule "extern/html-textview"]
path = extern/html-textview
url = https://github.com/open-keychain/html-textview.git

View File

@ -12,16 +12,16 @@ dependencies {
compile 'com.android.support:appcompat-v7:19.0.1' compile 'com.android.support:appcompat-v7:19.0.1'
compile project(':OpenKeychain-API:libraries:openpgp-api-library') compile project(':OpenKeychain-API:libraries:openpgp-api-library')
compile project(':OpenKeychain-API:libraries:openkeychain-api-library') compile project(':OpenKeychain-API:libraries:openkeychain-api-library')
compile project(':libraries:HtmlTextView') compile project(':extern:html-textview')
compile project(':libraries:StickyListHeaders:library') compile project(':extern:StickyListHeaders:library')
compile project(':libraries:AndroidBootstrap') compile project(':extern:AndroidBootstrap:AndroidBootstrap')
compile project(':libraries:zxing') compile project(':extern:zxing-qr-code')
compile project(':libraries:zxing-android-integration') compile project(':extern:zxing-android-integration')
compile project(':libraries:spongycastle:core') compile project(':extern:spongycastle:core')
compile project(':libraries:spongycastle:pg') compile project(':extern:spongycastle:pg')
compile project(':libraries:spongycastle:pkix') compile project(':extern:spongycastle:pkix')
compile project(':libraries:spongycastle:prov') compile project(':extern:spongycastle:prov')
compile project(':libraries:Android-AppMsg:library') compile project(':extern:AppMsg:library')
// Dependencies for the `testLocal` task, make sure to list all your global dependencies here as well // Dependencies for the `testLocal` task, make sure to list all your global dependencies here as well
testLocalCompile 'junit:junit:4.11' testLocalCompile 'junit:junit:4.11'
@ -31,16 +31,16 @@ dependencies {
testLocalCompile 'com.android.support:appcompat-v7:19.0.1' testLocalCompile 'com.android.support:appcompat-v7:19.0.1'
testLocalCompile project(':OpenKeychain-API:libraries:openpgp-api-library') testLocalCompile project(':OpenKeychain-API:libraries:openpgp-api-library')
testLocalCompile project(':OpenKeychain-API:libraries:openkeychain-api-library') testLocalCompile project(':OpenKeychain-API:libraries:openkeychain-api-library')
testLocalCompile project(':libraries:HtmlTextView') testLocalCompile project(':extern:html-textview')
testLocalCompile project(':libraries:StickyListHeaders:library') testLocalCompile project(':extern:StickyListHeaders:library')
testLocalCompile project(':libraries:AndroidBootstrap') testLocalCompile project(':extern:AndroidBootstrap:AndroidBootstrap')
testLocalCompile project(':libraries:zxing') testLocalCompile project(':extern:zxing-qr-code')
testLocalCompile project(':libraries:zxing-android-integration') testLocalCompile project(':extern:zxing-android-integration')
testLocalCompile project(':libraries:spongycastle:core') testLocalCompile project(':extern:spongycastle:core')
testLocalCompile project(':libraries:spongycastle:pg') testLocalCompile project(':extern:spongycastle:pg')
testLocalCompile project(':libraries:spongycastle:pkix') testLocalCompile project(':extern:spongycastle:pkix')
testLocalCompile project(':libraries:spongycastle:prov') testLocalCompile project(':extern:spongycastle:prov')
testLocalCompile project(':libraries:Android-AppMsg:library') testLocalCompile project(':extern:AppMsg:library')
} }
android { android {

View File

@ -69,7 +69,6 @@ import org.sufficientlysecure.keychain.util.Log;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
import se.emilsjolander.stickylistheaders.StickyListHeadersListView; import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
@ -150,16 +149,14 @@ public class KeyListFragment extends Fragment
mStickyList.setAreHeadersSticky(true); mStickyList.setAreHeadersSticky(true);
mStickyList.setDrawingListUnderStickyHeader(false); mStickyList.setDrawingListUnderStickyHeader(false);
mStickyList.setFastScrollEnabled(true); mStickyList.setFastScrollEnabled(true);
try {
mStickyList.setFastScrollAlwaysVisible(true);
} catch (ApiLevelTooLowException e) {
}
/* /*
* ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only * ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only
* available for Android >= 3.0 * available for Android >= 3.0
*/ */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mStickyList.setFastScrollAlwaysVisible(true);
mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() { mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() {

View File

@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager;
@ -41,7 +42,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
import se.emilsjolander.stickylistheaders.StickyListHeadersListView; import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
@ -100,9 +100,8 @@ public class ViewKeyCertsFragment extends Fragment
mStickyList.setFastScrollEnabled(true); mStickyList.setFastScrollEnabled(true);
mStickyList.setOnItemClickListener(this); mStickyList.setOnItemClickListener(this);
try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mStickyList.setFastScrollAlwaysVisible(true); mStickyList.setFastScrollAlwaysVisible(true);
} catch (ApiLevelTooLowException e) {
} }
mStickyList.setEmptyView(getActivity().findViewById(R.id.empty)); mStickyList.setEmptyView(getActivity().findViewById(R.id.empty));

View File

@ -30,14 +30,15 @@ Development mailinglist at http://groups.google.com/d/forum/openpgp-keychain-dev
### Build with Gradle ### Build with Gradle
1. Have Android SDK "tools", "platform-tools", and "build-tools" directories in your PATH (http://developer.android.com/sdk/index.html) 1. Get all external submodules with ``git submodule update --init --recursive``
2. Open the Android SDK Manager (shell command: ``android``). 2. Have Android SDK "tools", "platform-tools", and "build-tools" directories in your PATH (http://developer.android.com/sdk/index.html)
3. Open the Android SDK Manager (shell command: ``android``).
Expand the Tools directory and select "Android SDK Build-tools (Version 19.0.3)". Expand the Tools directory and select "Android SDK Build-tools (Version 19.0.3)".
Expand the Extras directory and install "Android Support Repository" Expand the Extras directory and install "Android Support Repository"
Select everything for the newest SDK Platform (API-Level 19) Select everything for the newest SDK Platform (API-Level 19)
3. Export ANDROID_HOME pointing to your Android SDK 4. Export ANDROID_HOME pointing to your Android SDK
4. Execute ``./gradlew build`` 5. Execute ``./gradlew build``
5. You can install the app with ``adb install -r OpenKeychain/build/apk/OpenKeychain-debug-unaligned.apk`` 6. You can install the app with ``adb install -r OpenKeychain/build/apk/OpenKeychain-debug-unaligned.apk``
### Build API Demo with Gradle ### Build API Demo with Gradle

1
extern/AndroidBootstrap vendored Submodule

@ -0,0 +1 @@
Subproject commit bfa160c4ef3a1a53aebd68aca9c05b8e546219e0

1
extern/AppMsg vendored Submodule

@ -0,0 +1 @@
Subproject commit ca714df97bfce67a7a9a1efefd2c49645b6f22e4

1
extern/StickyListHeaders vendored Submodule

@ -0,0 +1 @@
Subproject commit efe46c21143cc54a2394303a67822f14580d1d20

1
extern/html-textview vendored Submodule

@ -0,0 +1 @@
Subproject commit 30fbf60ccfa8732e8fc4d3c97b94c4809ef871a5

1
extern/spongycastle vendored Submodule

@ -0,0 +1 @@
Subproject commit eb2c35bd0602d05a65c10c86b9c9834ebd1a81c6

1
extern/zxing-android-integration vendored Submodule

@ -0,0 +1 @@
Subproject commit 34029d4dcac81ec06137a046a189dac608e76efe

1
extern/zxing-qr-code vendored Submodule

@ -0,0 +1 @@
Subproject commit 50193905fd8cef92140ea242f77b04bb31391c9e

View File

@ -1,36 +0,0 @@
#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

View File

@ -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.

View File

@ -1,117 +0,0 @@
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. Lets 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

View File

@ -1,12 +0,0 @@
<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>

View File

@ -1,22 +0,0 @@
apply plugin: 'android-library'
android {
compileSdkVersion 19
buildToolsVersion '19.0.3'
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'
}

View File

@ -1,71 +0,0 @@
<?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>

View File

@ -1,15 +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-19
android.library=true

View File

@ -1,20 +0,0 @@
<?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>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="alert">#CC0000</color>
<color name="confirm">#FF8800</color>
<color name="info">#669900</color>
</resources>

View File

@ -1,587 +0,0 @@
/*
* 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;
}
}
}

View File

@ -1,340 +0,0 @@
/*
* 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) {}
}
}

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.beardedhen.androidbootstrap"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="17" />
<application/>
</manifest>

View File

@ -1,17 +0,0 @@
apply plugin: 'android-library'
android {
compileSdkVersion 19
buildToolsVersion "19.0.3"
defaultConfig {
minSdkVersion 7
targetSdkVersion 19
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
res.srcDirs = ['res']
}
}
}

View File

@ -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 *;
#}

View File

@ -1,15 +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-19
android.library=true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_danger_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_danger_edge" />
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_danger_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_danger_disabled_edge" />
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_danger" />
<stroke android:width="1dp" android:color="@color/bbutton_danger_edge" />
</shape></item>
</selector>

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_danger_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_danger_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_danger_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_danger_disabled_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_danger" />
<stroke android:width="1dp" android:color="@color/bbutton_danger_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
</selector>

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_default_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_default_edge" />
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_default_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_default_disabled_edge" />
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_default" />
<stroke android:width="1dp" android:color="@color/bbutton_default_edge" />
</shape></item>
</selector>

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_default_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_default_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_default_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_default_disabled_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_default" />
<stroke android:width="1dp" android:color="@color/bbutton_default_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
</selector>

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_info_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_info_edge" />
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_info_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_info_disabled_edge" />
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_info" />
<stroke android:width="1dp" android:color="@color/bbutton_info_edge" />
</shape></item>
</selector>

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_info_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_info_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_info_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_info_disabled_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_info" />
<stroke android:width="1dp" android:color="@color/bbutton_info_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
</selector>

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_inverse_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_inverse_edge" />
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_inverse_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_inverse_disabled_edge" />
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_inverse" />
<stroke android:width="1dp" android:color="@color/bbutton_inverse_edge" />
</shape></item>
</selector>

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_inverse_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_inverse_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_inverse_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_inverse_disabled_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_inverse" />
<stroke android:width="1dp" android:color="@color/bbutton_inverse_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
</selector>

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_primary_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_primary_edge" />
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_primary_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_primary_disabled_edge" />
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_primary" />
<stroke android:width="1dp" android:color="@color/bbutton_primary_edge" />
</shape></item>
</selector>

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_primary_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_primary_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_primary_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_primary_disabled_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_primary" />
<stroke android:width="1dp" android:color="@color/bbutton_primary_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
</selector>

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_success_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_success_edge" />
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_success_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_success_disabled_edge" />
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_success" />
<stroke android:width="1dp" android:color="@color/bbutton_success_edge" />
</shape></item>
</selector>

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_success_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_success_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_success_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_success_disabled_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_success" />
<stroke android:width="1dp" android:color="@color/bbutton_success_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
</selector>

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_warning_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_warning_edge" />
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_warning_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_warning_disabled_edge" />
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_warning" />
<stroke android:width="1dp" android:color="@color/bbutton_warning_edge" />
</shape></item>
</selector>

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape>
<solid android:color="@color/bbutton_warning_pressed" />
<stroke android:width="1dp" android:color="@color/bbutton_warning_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_warning_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_warning_disabled_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
<item><shape>
<solid android:color="@color/bbutton_warning" />
<stroke android:width="1dp" android:color="@color/bbutton_warning_edge" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius"/>
</shape></item>
</selector>

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item><shape>
<solid android:color="@color/bthumbnail_background" />
<stroke android:width="1dp" android:color="@color/bthumbnail_border" />
<corners android:radius="@dimen/bthumbnail_rounded_corner_radius"/>
</shape></item>
</selector>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item><shape>
<solid android:color="@color/bthumbnail_background" />
<stroke android:width="1dp" android:color="@color/bthumbnail_border" />
</shape></item>
</selector>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item><shape android:shape="rectangle">
<solid android:color="@color/bthumbnail_placeholder" />
</shape></item>
</selector>

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"><shape>
<solid android:color="@color/white" />
<stroke android:width="2dp" android:color="@color/bbutton_primary" />
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_edittext_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_edittext_border" />
</shape></item>
<item><shape android:shape="rectangle">
<solid android:color="@color/white" />
<stroke android:width="1dp" android:color="@color/bbutton_edittext_border" />
</shape></item>
</selector>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"><shape>
<solid android:color="@color/white" />
<stroke android:width="2dp" android:color="@color/bbutton_danger" />
</shape></item>
<item><shape android:shape="rectangle">
<solid android:color="@color/white" />
<stroke android:width="1dp" android:color="@color/bbutton_danger" />
</shape></item>
</selector>

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"><shape>
<solid android:color="@color/white" />
<stroke android:width="2dp" android:color="@color/bbutton_primary" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius" />
</shape></item>
<item android:state_enabled="false"><shape>
<solid android:color="@color/bbutton_edittext_disabled" />
<stroke android:width="1dp" android:color="@color/bbutton_edittext_border" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius" />
</shape></item>
<item><shape android:shape="rectangle">
<solid android:color="@color/white" />
<stroke android:width="1dp" android:color="@color/bbutton_edittext_border" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius" />
</shape></item>
</selector>

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"><shape>
<solid android:color="@color/white" />
<stroke android:width="2dp" android:color="@color/bbutton_danger" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius" />
</shape></item>
<item><shape android:shape="rectangle">
<solid android:color="@color/white" />
<stroke android:width="1dp" android:color="@color/bbutton_danger" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius" />
</shape></item>
</selector>

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"><shape>
<solid android:color="@color/white" />
<stroke android:width="2dp" android:color="@color/bbutton_success" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius" />
</shape></item>
<item><shape android:shape="rectangle">
<solid android:color="@color/white" />
<stroke android:width="1dp" android:color="@color/bbutton_success" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius" />
</shape></item>
</selector>

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"><shape>
<solid android:color="@color/white" />
<stroke android:width="2dp" android:color="@color/bbutton_warning" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius" />
</shape></item>
<item><shape android:shape="rectangle">
<solid android:color="@color/white" />
<stroke android:width="1dp" android:color="@color/bbutton_warning" />
<corners android:radius="@dimen/bbuton_rounded_corner_radius" />
</shape></item>
</selector>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"><shape>
<solid android:color="@color/white" />
<stroke android:width="2dp" android:color="@color/bbutton_success" />
</shape></item>
<item><shape android:shape="rectangle">
<solid android:color="@color/white" />
<stroke android:width="1dp" android:color="@color/bbutton_success" />
</shape></item>
</selector>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"><shape>
<solid android:color="@color/white" />
<stroke android:width="2dp" android:color="@color/bbutton_warning" />
</shape></item>
<item><shape android:shape="rectangle">
<solid android:color="@color/white" />
<stroke android:width="1dp" android:color="@color/bbutton_warning" />
</shape></item>
</selector>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/bthumbnail_placeholder"/>
</shape>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:shape="oval">
<solid android:color="@color/bthumbnail_background" />
<stroke android:width="1dp" android:color="@color/bthumbnail_border" />
</shape>
</item>
</selector>

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:shape="oval">
<solid android:color="@color/bthumbnail_background" />
</shape>
</item>
</selector>

View File

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/layout"
android:duplicateParentState="true"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/lblLeft"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingLeft="15dp"
android:visibility="gone"
android:layout_gravity="center_vertical"
/>
<TextView
android:id="@+id/lblMiddle"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:layout_gravity="center"
android:gravity="center_horizontal"
android:visibility="gone"
/>
<TextView
android:id="@+id/lblRight"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingRight="15dp"
android:visibility="gone"
android:layout_gravity="center_vertical"
/>
</LinearLayout>

View File

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:duplicateParentState="true"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/lblLeft"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:paddingLeft="15dp"
android:visibility="gone"
android:gravity="center_vertical"
android:layout_alignParentLeft="true"
/>
<TextView
android:id="@+id/lblRight"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:paddingRight="15dp"
android:visibility="gone"
android:gravity="center_vertical"
android:layout_alignParentRight="true"
/>
<TextView
android:id="@+id/lblMiddle"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:visibility="gone"
android:gravity="left|center_vertical"
android:layout_toLeftOf="@id/lblRight"
android:layout_toRightOf="@id/lblLeft"
/>
</RelativeLayout>

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/layout"
android:orientation="horizontal">
<EditText
android:id="@+id/txtText"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:layout_gravity="center"
android:hint=""
/>
</LinearLayout>

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/container"
android:duplicateParentState="true"
android:padding="@dimen/padding_small"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/placeholder"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<com.beardedhen.androidbootstrap.utils.AutoResizeTextView
android:id="@+id/dimensionsLabel"
android:layout_width="match_parent"
android:layout_height="100dp"
android:ellipsize="none"
android:gravity="center"
android:maxLines="1"
android:textSize="100sp"
android:textColor="@color/bthumbnail_font"/>
</LinearLayout>
</LinearLayout>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/container"
android:duplicateParentState="true"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/placeholder"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="@+id/image"/>
<com.beardedhen.androidbootstrap.utils.AutoResizeTextView
android:id="@+id/dimensionsLabel"
android:layout_width="match_parent"
android:layout_height="100dp"
android:ellipsize="none"
android:gravity="center"
android:maxLines="1"
android:textSize="100sp"
android:textColor="@color/bthumbnail_font"/>
</LinearLayout>
</LinearLayout>

View File

@ -1,14 +0,0 @@
<?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:id="@+id/layout"
android:orientation="horizontal">
<TextView
android:id="@+id/lblText"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:padding="3dp"
/>
</LinearLayout>

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/lblTitle"
android:gravity="left"
/>
</LinearLayout>

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/lblTitle"
android:gravity="center"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/lblSubTitle"
android:gravity="center"
/>
</LinearLayout>

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/lblColA"
android:gravity="center"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/lblColB"
android:gravity="center"
/>
</LinearLayout>

View File

@ -1,9 +0,0 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_settings"/>
</menu>

View File

@ -1,8 +0,0 @@
<resources>
<!--
Customize dimensions originally defined in res/values/dimens.xml (such as
screen margins) for sw600dp devices (e.g. 7" tablets) here.
-->
</resources>

View File

@ -1,9 +0,0 @@
<resources>
<!--
Customize dimensions originally defined in res/values/dimens.xml (such as
screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
-->
<dimen name="activity_horizontal_margin">128dp</dimen>
</resources>

View File

@ -1,11 +0,0 @@
<resources>
<!--
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
<!-- API 11 theme customizations can go here. -->
</style>
</resources>

View File

@ -1,12 +0,0 @@
<resources>
<!--
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- API 14 theme customizations can go here. -->
</style>
</resources>

View File

@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="BootstrapButton">
<attr name="bb_type" format="string"/>
<attr name="bb_icon_left" format="string"/>
<attr name="bb_icon_right" format="string"/>
<attr name="bb_roundedCorners" format="boolean"/>
<attr name="bb_text_alignment" format="string"/>
<attr name="bb_size" format="string"/>
<attr name="bb_text_gravity" format="string"/>
<attr name="android:textSize"/>
<attr name="android:text"/>
<attr name="android:enabled"/>
<attr name="android:layout_width"/>
</declare-styleable>
<declare-styleable name="FontAwesomeText">
<attr name="fa_icon" format="string"/>
<attr name="android:textSize"/>
<attr name="android:textColor"/>
</declare-styleable>
<declare-styleable name="BootstrapEditText">
<attr name="be_roundedCorners" format="boolean"/>
<attr name="be_state" format="string"/>
<attr name="android:textSize"/>
<attr name="android:text"/>
<attr name="android:hint"/>
<attr name="android:enabled"/>
</declare-styleable>
<declare-styleable name="BootstrapThumbnail">
<attr name="bt_roundedCorners" format="boolean"/>
<attr name="bt_image" format="integer"/>
<attr name="bt_width" format="dimension"/>
<attr name="bt_height" format="dimension"/>
<attr name="bt_inside_padding" format="dimension"/>
<attr name="android:text"/>
</declare-styleable>
<declare-styleable name="BootstrapCircleThumbnail">
<attr name="bct_image" format="integer"/>
<attr name="bct_size" format="string" />
<attr name="bct_minimal" format="boolean" />
<attr name="android:text"/>
</declare-styleable>
</resources>

View File

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="white">#ffffffff</color>
<color name="black">#ff000000</color>
<color name="bbutton_edittext_border">#ccc</color>
<color name="bbutton_edittext_disabled">#ffe0e0e0</color>
<color name="bbutton_primary">#ff428bca</color>
<color name="bbutton_primary_edge">#ff357ebd</color>
<color name="bbutton_primary_pressed">#ff3276b1</color>
<color name="bbutton_primary_pressed_edge">#ff285e8e</color>
<color name="bbutton_primary_disabled">#a5428bca</color>
<color name="bbutton_primary_disabled_edge">#a5357ebd</color>
<color name="bbutton_danger">#ffd9534f</color>
<color name="bbutton_danger_edge">#ffd43f3a</color>
<color name="bbutton_danger_pressed">#ffd2322d</color>
<color name="bbutton_danger_pressed_edge">#ffac2925</color>
<color name="bbutton_danger_disabled">#a5d9534f</color>
<color name="bbutton_danger_disabled_edge">#a5d43f3a</color>
<color name="bbutton_success">#ff5cb85c</color>
<color name="bbutton_success_edge">#ff4cae4c</color>
<color name="bbutton_success_pressed">#ff47a447</color>
<color name="bbutton_success_pressed_edge">#ff398439</color>
<color name="bbutton_success_disabled">#a55cb85c</color>
<color name="bbutton_success_disabled_edge">#a54cae4c</color>
<color name="bbutton_warning">#fff0ad4e</color>
<color name="bbutton_warning_edge">#ffeea236</color>
<color name="bbutton_warning_pressed">#ffed9c28</color>
<color name="bbutton_warning_pressed_edge">#ffd58512</color>
<color name="bbutton_warning_disabled">#a5f0ad4e</color>
<color name="bbutton_warning_disabled_edge">#a5eea236</color>
<color name="bbutton_info">#ff5bc0de</color>
<color name="bbutton_info_edge">#ff46b8da</color>
<color name="bbutton_info_pressed">#ff39b3d7</color>
<color name="bbutton_info_pressed_edge">#ff269abc</color>
<color name="bbutton_info_disabled">#a55bc0de</color>
<color name="bbutton_info_disabled_edge">#a546b8da</color>
<color name="bbutton_default">#ffffffff</color>
<color name="bbutton_default_edge">#ffcccccc</color>
<color name="bbutton_default_pressed">#ffebebeb</color>
<color name="bbutton_default_pressed_edge">#ffadadad</color>
<color name="bbutton_default_disabled">#a5ffffff</color>
<color name="bbutton_default_disabled_edge">#a5cccccc</color>
<color name="bbutton_inverse">#ff0a0a0a</color>
<color name="bbutton_inverse_edge">#ff141414</color>
<color name="bbutton_inverse_pressed">#ff1f1f1f</color>
<color name="bbutton_inverse_pressed_edge">#ff292929</color>
<color name="bbutton_inverse_disabled">#a50a0a0a</color>
<color name="bbutton_inverse_disabled_edge">#a5141414</color>
<color name="bthumbnail_background">#ffffffff</color>
<color name="bthumbnail_placeholder">#e9e9e9</color>
<color name="bthumbnail_border">#dbdbdb</color>
<color name="bthumbnail_font">#7e7e7e</color>
</resources>

View File

@ -1,14 +0,0 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="bbuton_rounded_corner_radius">5dp</dimen>
<dimen name="bthumbnail_rounded_corner_radius">3dp</dimen>
<dimen name="padding_micro">4dp</dimen>
<dimen name="padding_small">8dp</dimen>
<dimen name="padding_medium">12dp</dimen>
<dimen name="padding_large">16dp</dimen>
</resources>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">BButton</string>
<string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string>
</resources>

View File

@ -1,16 +0,0 @@
<resources>
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Light">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
</resources>

View File

@ -1,445 +0,0 @@
package com.beardedhen.androidbootstrap;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.beardedhen.androidbootstrap.R;
public class BootstrapButton extends FrameLayout {
private static Map<String, BootstrapTypes> bbuttonTypeMap;
private static Map<String, BootstrapTypes> bbuttonTypeMapRounded;
private static Typeface font;
private static Map<String, String> faMap;
private TextView lblMiddle;
private TextView lblRight;
private TextView lblLeft;
private ViewGroup layout;
private boolean roundedCorners = false;
private boolean fillparent = false;
private static final String FA_ICON_QUESTION = "fa-question";
static{
bbuttonTypeMap = new HashMap<String, BootstrapTypes>();
bbuttonTypeMap.put("default", BootstrapTypes.DEFAULT);
bbuttonTypeMap.put("primary", BootstrapTypes.PRIMARY);
bbuttonTypeMap.put("success", BootstrapTypes.SUCCESS);
bbuttonTypeMap.put("info", BootstrapTypes.INFO);
bbuttonTypeMap.put("warning", BootstrapTypes.WARNING);
bbuttonTypeMap.put("danger", BootstrapTypes.DANGER);
bbuttonTypeMap.put("inverse", BootstrapTypes.INVERSE);
bbuttonTypeMapRounded = new HashMap<String, BootstrapTypes>();
bbuttonTypeMapRounded.put("default", BootstrapTypes.DEFAULT_ROUNDED);
bbuttonTypeMapRounded.put("primary", BootstrapTypes.PRIMARY_ROUNDED);
bbuttonTypeMapRounded.put("success", BootstrapTypes.SUCCESS_ROUNDED);
bbuttonTypeMapRounded.put("info", BootstrapTypes.INFO_ROUNDED);
bbuttonTypeMapRounded.put("warning", BootstrapTypes.WARNING_ROUNDED);
bbuttonTypeMapRounded.put("danger", BootstrapTypes.DANGER_ROUNDED);
bbuttonTypeMapRounded.put("inverse", BootstrapTypes.INVERSE_ROUNDED);
faMap = FontAwesome.getFaMap();
}
public BootstrapButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialise(attrs);
}
public BootstrapButton(Context context, AttributeSet attrs) {
super(context, attrs);
initialise(attrs);
}
public BootstrapButton(Context context) {
super(context);
initialise(null);
}
//set up the bootstrap types
private enum BootstrapTypes
{
DEFAULT(R.drawable.bbuton_default, R.color.black),
PRIMARY(R.drawable.bbuton_primary, R.color.white),
SUCCESS(R.drawable.bbuton_success, R.color.white),
INFO(R.drawable.bbuton_info, R.color.white),
WARNING(R.drawable.bbuton_warning, R.color.white),
DANGER(R.drawable.bbuton_danger, R.color.white),
INVERSE(R.drawable.bbuton_inverse, R.color.white),
DEFAULT_ROUNDED(R.drawable.bbuton_default_rounded, R.color.black),
PRIMARY_ROUNDED(R.drawable.bbuton_primary_rounded, R.color.white),
SUCCESS_ROUNDED(R.drawable.bbuton_success_rounded, R.color.white),
INFO_ROUNDED(R.drawable.bbuton_info_rounded, R.color.white),
WARNING_ROUNDED(R.drawable.bbuton_warning_rounded, R.color.white),
DANGER_ROUNDED(R.drawable.bbuton_danger_rounded, R.color.white),
INVERSE_ROUNDED(R.drawable.bbuton_inverse_rounded, R.color.white);
private int backgroundDrawable;
private int textColour;
BootstrapTypes(int backgroundDrawable, int textColour)
{
this.backgroundDrawable = backgroundDrawable;
this.textColour = textColour;
}
}
private void initialise( AttributeSet attrs )
{
LayoutInflater inflator = (LayoutInflater)getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
//get font
readFont(getContext());
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.BootstrapButton);
//defaults
BootstrapTypes type = null;
String bootstrapType = "default";
String iconLeft = "";
String iconRight = "";
String text = "";
//boolean roundedCorners = false;
float fontSize = 14.0f;
float scale = getResources().getDisplayMetrics().density; //for padding
String size = "default";
int paddingA = (int) (10 *scale + 0.5f);
int paddingB = (int) (15 *scale + 0.5f);
//attribute values
if (a.getString(R.styleable.BootstrapButton_bb_type) != null) {
bootstrapType = a.getString(R.styleable.BootstrapButton_bb_type);
}
if (a.getString(R.styleable.BootstrapButton_bb_roundedCorners) != null) {
roundedCorners = a.getBoolean(R.styleable.BootstrapButton_bb_roundedCorners, false) ;
}
if(a.getString(R.styleable.BootstrapButton_bb_size) != null) {
size = a.getString(R.styleable.BootstrapButton_bb_size);
}
if ( a.getString(R.styleable.BootstrapButton_bb_icon_left) != null) {
iconLeft = a.getString(R.styleable.BootstrapButton_bb_icon_left );
}
if(a.getString(R.styleable.BootstrapButton_bb_icon_right) != null) {
iconRight = a.getString(R.styleable.BootstrapButton_bb_icon_right );
}
if(a.getString(R.styleable.BootstrapButton_android_text) != null) {
text = a.getString(R.styleable.BootstrapButton_android_text);
}
String gravity = "";
if(a.getString(R.styleable.BootstrapButton_bb_text_gravity) != null) {
gravity = a.getString(R.styleable.BootstrapButton_bb_text_gravity);
}
boolean enabled = true;
if(a.getString(R.styleable.BootstrapButton_android_enabled) != null) {
enabled = a.getBoolean(R.styleable.BootstrapButton_android_enabled, true);
}
int layoutWidth = 0;
if(a.getString(R.styleable.BootstrapButton_android_layout_width) != null) {
layoutWidth = a.getInt(R.styleable.BootstrapButton_android_layout_width, 0);
}
//works even if it's fill_parent or match_parent
if( (layoutWidth == LayoutParams.MATCH_PARENT)) {
fillparent = true;
}
if(a.getString(R.styleable.BootstrapButton_android_textSize) != null) {
//font sizes
String xmlProvidedSize = attrs.getAttributeValue(
"http://schemas.android.com/apk/res/android", "textSize");
final Pattern PATTERN_FONT_SIZE = Pattern
.compile("([0-9]+[.]?[0-9]*)sp");
Matcher m = PATTERN_FONT_SIZE.matcher(xmlProvidedSize);
if (m.find()) {
if (m.groupCount() == 1) {
fontSize = Float.valueOf(m.group(1));
}
}
}
a.recycle();
View v = null;
if(fillparent){
v = inflator.inflate(R.layout.bootstrap_button_fill, null, false);
} else {
v = inflator.inflate(R.layout.bootstrap_button, null, false);
}
//set up font sizes and padding for different button sizes
if(size.equals("large")){
fontSize = 20.0f;
paddingA = (int) (15 *scale + 0.5f);;
paddingB = (int) (20 *scale + 0.5f);;
}
if(size.equals("small")){
fontSize = 12.0f;
paddingA = (int) (5 *scale + 0.5f);;
paddingB = (int) (10 *scale + 0.5f);;
}
if(size.equals("xsmall")){
fontSize = 10.0f;
paddingA = (int) (2 *scale + 0.5f);;
paddingB = (int) (5 *scale + 0.5f);;
}
//get layout items
layout = (ViewGroup) v.findViewById(R.id.layout);
lblLeft = (TextView) v.findViewById(R.id.lblLeft);
lblMiddle = (TextView) v.findViewById(R.id.lblMiddle);
lblRight = (TextView) v.findViewById(R.id.lblRight);
//set the background
//setBootstrapType(bootstrapType);
//get the correct background type
if(roundedCorners == true)
{
type = bbuttonTypeMapRounded.get(bootstrapType);
} else {
type = bbuttonTypeMap.get(bootstrapType);
}
//set up as default
if (type == null)
{
type = BootstrapTypes.DEFAULT;
}
//apply the background type
layout.setBackgroundResource(type.backgroundDrawable);
lblLeft.setTextColor(getResources().getColor(type.textColour));
lblMiddle.setTextColor(getResources().getColor(type.textColour));
lblRight.setTextColor(getResources().getColor(type.textColour));
//set the font awesome icon typeface
lblLeft.setTypeface(font);
lblRight.setTypeface(font);
//set up the font size
lblLeft.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
lblMiddle.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
lblRight.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
//deal with gravity
if(gravity.length() > 0) {
setTextGravity(gravity);
}
boolean onlyIcon = true;
//set the text
if(text.length() > 0){
lblMiddle.setText(text );
lblMiddle.setVisibility(View.VISIBLE);
onlyIcon = false;
}
//set up the padding
if (iconLeft.length() > 0) {
//lblLeft.setText(iconLeft);
setLeftIcon(iconLeft);
lblLeft.setVisibility(View.VISIBLE);
if (onlyIcon == false){
lblLeft.setPadding(paddingB, 0, 0, 0);
} else {
lblLeft.setPadding(paddingB, 0, paddingB, 0);
}
//padding for symmetry
if ( ( iconRight.length() == 0) && onlyIcon == false ) {
lblMiddle.setPadding(paddingA, 0, (int) paddingB, 0);
}
}
if (iconRight.length() > 0) {
//lblRight.setText(iconRight);
setRightIcon(iconRight);
lblRight.setVisibility(View.VISIBLE);
if (onlyIcon == false){
lblRight.setPadding(0, 0, paddingB, 0);
}else {
lblRight.setPadding(paddingB, 0, paddingB, 0);
}
//padding for symmetry
if ( (iconLeft.length() == 0) && onlyIcon == false ) {
lblMiddle.setPadding(paddingB, 0, (int) paddingA, 0);
}
}
if(iconLeft.length() > 0 && iconRight.length() > 0 )
{
lblMiddle.setPadding(paddingA, 0, paddingA, 0);
}
this.setClickable(true);
this.setEnabled(enabled);
layout.setPadding(0, paddingB, 0, paddingB);
addView(v);
}
//static class to read in font
private static void readFont(Context context)
{
if(font == null){
try {
font = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
} catch (Exception e) {
Log.e("BootstrapButton", "Could not get typeface because " + e.getMessage());
font = Typeface.DEFAULT;
}
}
}
/**
* Changes the button text
* @param text - String value for what is displayed on the button
*/
public void setText(String text) {
lblMiddle.setText(text);
}
/**
* Changes the left icon on a BootstrapButton
* @param leftIcon- String value for the icon as per http://fortawesome.github.io/Font-Awesome/cheatsheet/
*/
public void setLeftIcon(String leftIcon) {
String icon = faMap.get(leftIcon);
if (icon == null)
{
icon = faMap.get(FA_ICON_QUESTION);
}
lblLeft.setText(icon);
}
/**
* Changes the right icon on a BootstrapButton
* @param rightIcon - String value for the icon as per http://fortawesome.github.io/Font-Awesome/cheatsheet/
*/
public void setRightIcon(String rightIcon) {
String icon = faMap.get(rightIcon);
if (icon == null)
{
icon = faMap.get(FA_ICON_QUESTION);
}
lblRight.setText(icon);
}
/**
* Changes the type of BootstrapButton
* @param bootstrapType - String value for the type of button e.g. "primary"
*/
public void setBootstrapType(String bootstrapType) {
BootstrapTypes type = null;
//get the correct background type
if (roundedCorners == true) {
type = bbuttonTypeMapRounded.get(bootstrapType);
} else {
type = bbuttonTypeMap.get(bootstrapType);
}
//set up as default
if (type == null) {
type = BootstrapTypes.DEFAULT;
}
layout.setBackgroundResource(type.backgroundDrawable);
lblLeft.setTextColor(getResources().getColor(type.textColour));
lblMiddle.setTextColor(getResources().getColor(type.textColour));
lblRight.setTextColor(getResources().getColor(type.textColour));
}
/**
* Specifies whether the BootstrapButton is enabled or disabled
* @param enabled - boolean state for either enabled or disabled
*/
public void setBootstrapButtonEnabled(boolean enabled)
{
this.setEnabled(enabled);
}
/**
* Changes the gravity for the text on a bootstrap button that is not wrap_content
* @param gravity - string for either center, right, or left.
*/
public void setTextGravity(String gravity) {
if(gravity.equals("left")) {
lblMiddle.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
} else if (gravity.equals("center")) {
lblMiddle.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
} else if (gravity.equals("right")) {
lblMiddle.setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL);
}
}
}

View File

@ -1,215 +0,0 @@
package com.beardedhen.androidbootstrap;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.beardedhen.androidbootstrap.utils.ImageUtils;
public class BootstrapCircleThumbnail extends FrameLayout
{
private static final int PADDING_SMALL = 4;
private static final int PADDING_MEDIUM = 4;
private static final int PADDING_LARGE = 6;
private static final int PADDING_XLARGE = 8;
private static final int SIZE_SMALL = 48; //dp total size (outer circle)
private static final int SIZE_MEDIUM = 80;//dp
private static final int SIZE_LARGE = 112;//dp
private static final int SIZE_XLARGE = 176;//dp
private static final int SIZE_DEFAULT = SIZE_MEDIUM;
private static final String SMALL = "small";
private static final String MEDIUM = "medium";
private static final String LARGE = "large";
private static final String XLARGE = "xlarge";
private LinearLayout container;
private LinearLayout placeholder;
private ImageView image;
private TextView dimensionsLabel;
private String size = MEDIUM;
private boolean minimal = false;//minimal means display just the image, no padding
private String text = "";
private int imageWidth = SIZE_DEFAULT;
private int imageHeight = SIZE_DEFAULT;
private int padding = 0;
public BootstrapCircleThumbnail(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
initialise(attrs);
}
public BootstrapCircleThumbnail(Context context, AttributeSet attrs)
{
super(context, attrs);
initialise(attrs);
}
public BootstrapCircleThumbnail(Context context)
{
super(context);
initialise(null);
}
private void initialise( AttributeSet attrs )
{
LayoutInflater inflator = (LayoutInflater)getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.BootstrapCircleThumbnail);
int imageDrawable = 0;
if(a.getString(R.styleable.BootstrapCircleThumbnail_bct_image) != null)
{
imageDrawable = a.getResourceId(R.styleable.BootstrapCircleThumbnail_bct_image, 0);
}
if(a.getString(R.styleable.BootstrapCircleThumbnail_android_text) != null)
{
text = a.getString(R.styleable.BootstrapCircleThumbnail_android_text);
}
if(a.getString(R.styleable.BootstrapCircleThumbnail_bct_size) != null)
{
this.size = a.getString(R.styleable.BootstrapCircleThumbnail_bct_size);
}
if(a.getString(R.styleable.BootstrapCircleThumbnail_bct_minimal) != null)
{
this.minimal = a.getBoolean(R.styleable.BootstrapCircleThumbnail_bct_minimal, false);
}
a.recycle();
View v = inflator.inflate(R.layout.bootstrap_thumbnail_circle, null, false);
dimensionsLabel = (TextView) v.findViewById(R.id.dimensionsLabel);
container = (LinearLayout) v.findViewById(R.id.container);
placeholder = (LinearLayout) v.findViewById(R.id.placeholder);
image = (ImageView) v.findViewById(R.id.image);
float scale = getResources().getDisplayMetrics().density;
//small image
if(this.size.equals(SMALL))
{
padding = PADDING_SMALL;
imageWidth = SIZE_SMALL;
imageHeight = SIZE_SMALL;
}
else if(this.size.equals(MEDIUM))
{
padding = PADDING_MEDIUM;
imageWidth = SIZE_MEDIUM;
imageHeight = SIZE_MEDIUM;
}
else if(this.size.equals(LARGE))
{
padding = PADDING_LARGE;
imageWidth = SIZE_LARGE;
imageHeight = SIZE_LARGE;
}
else if(this.size.equals(XLARGE))
{
padding = PADDING_XLARGE;
imageWidth = SIZE_XLARGE;
imageHeight = SIZE_XLARGE;
}
//no valid size is given, set image to default size
else
{
padding = PADDING_MEDIUM;
imageWidth = SIZE_DEFAULT;
imageHeight = SIZE_DEFAULT;
}
//convert padding to pixels
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
int paddingPX = (int)((padding * scale) + 0.5);
//convert image size to pixels
int imageSizeWidthPX = (int)((imageWidth * scale) + 0.5);
int imageSizeHeightPX = (int)((imageHeight * scale) + 0.5);
//make inner image smaller to compensate for the padding so that entire circle including padding equals the size
//ex. small image = 48dp, small padding = 4dp, inner image = 48 - (4 * 2) = 40
if(this.minimal == false)
{
imageSizeWidthPX = imageSizeWidthPX - (paddingPX * 2);
imageSizeHeightPX = imageSizeHeightPX - (paddingPX * 2);
this.container.setPadding(paddingPX, paddingPX, paddingPX, paddingPX);
container.setBackgroundResource(R.drawable.thumbnail_circle_container);
}
else
{
container.setBackgroundResource(R.drawable.thumbnail_circle_minimal);
}
//if no image is given
if(imageDrawable == 0)
{
this.image.setVisibility(View.GONE);
placeholder.setLayoutParams(new LinearLayout.LayoutParams(imageSizeWidthPX, imageSizeHeightPX));
placeholder.setPadding(paddingPX, paddingPX, paddingPX, paddingPX);
//set placeholder image
placeholder.setBackgroundResource(R.drawable.thumbnail_circle);
this.dimensionsLabel.setText(text);
}
else
{
placeholder.setPadding(0, 0, 0, 0);
this.dimensionsLabel.setVisibility(View.GONE);
Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), imageDrawable);
Bitmap roundBitmap = ImageUtils.getCircleBitmap(bitmap, imageSizeWidthPX, imageSizeHeightPX);
image.setImageBitmap(roundBitmap);
}
this.addView(v);
}
public void setImage(int drawable)
{
Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), drawable);
float scale = getResources().getDisplayMetrics().density;
//convert image size to pixels
int widthPX = (int)((this.imageWidth * scale) + 0.5);
int heightPX = (int)((this.imageHeight * scale) + 0.5);
int paddingPX = (int)((this.padding * scale) + 0.5);
if(this.minimal == false)
{
widthPX = widthPX - (paddingPX * 2);
heightPX = heightPX - (paddingPX * 2);
}
Bitmap roundBitmap = ImageUtils.getCircleBitmap(bitmap, widthPX, heightPX);
image.setImageBitmap(roundBitmap);
invalidate();
requestLayout();
}
}

View File

@ -1,188 +0,0 @@
package com.beardedhen.androidbootstrap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.EditText;
public class BootstrapEditText extends EditText {
private boolean roundedCorners = false;
public BootstrapEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialise(attrs);
}
public BootstrapEditText(Context context, AttributeSet attrs) {
super(context, attrs);
initialise(attrs);
}
public BootstrapEditText(Context context) {
super(context);
initialise(null);
}
public static final String BOOTSTRAP_EDIT_TEXT_DEFAULT = "default";
public static final String BOOTSTRAP_EDIT_TEXT_SUCCESS = "success";
public static final String BOOTSTRAP_EDIT_TEXT_WARNING = "warning";
public static final String BOOTSTRAP_EDIT_TEXT_DANGER = "danger";
private void initialise( AttributeSet attrs )
{
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.BootstrapEditText);
//get defaults
float fontSize = 14.0f;
String state = "default";
String text = "";
String hint = "";
boolean enabled = true;
//font size
if (a.getString(R.styleable.BootstrapEditText_android_textSize) != null) {
String xmlProvidedSize = attrs.getAttributeValue( "http://schemas.android.com/apk/res/android", "textSize");
final Pattern PATTERN_FONT_SIZE = Pattern
.compile("([0-9]+[.]?[0-9]*)sp");
Matcher m = PATTERN_FONT_SIZE.matcher(xmlProvidedSize);
if (m.find()) {
if (m.groupCount() == 1) {
fontSize = Float.valueOf(m.group(1));
}
}
}
//rounded corners
if(a.getString(R.styleable.BootstrapEditText_be_roundedCorners) != null) {
roundedCorners = a.getBoolean(R.styleable.BootstrapEditText_be_roundedCorners, false);
}
//state
if(a.getString(R.styleable.BootstrapEditText_be_state) != null) {
state = a.getString(R.styleable.BootstrapEditText_be_state);
}
//text
if(a.getString(R.styleable.BootstrapEditText_android_text) != null) {
text = a.getString(R.styleable.BootstrapEditText_android_text);
}
//hint
if(a.getString(R.styleable.BootstrapEditText_android_hint) != null) {
hint = a.getString(R.styleable.BootstrapEditText_android_hint);
}
//enabled
if(a.getString(R.styleable.BootstrapEditText_android_enabled) != null) {
enabled = a.getBoolean(R.styleable.BootstrapEditText_android_enabled, true);
}
//set values
this.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
this.setText(text);
this.setHint(hint);
this.setEnabled(enabled);
if (enabled){
//work out the right background
setBackgroundDrawable(state);
}
a.recycle();
//addView(editTextView);
}
private void setBackgroundDrawable(String state)
{
if(roundedCorners){
this.setBackgroundResource(R.drawable.edittext_background_rounded);
} else {
this.setBackgroundResource(R.drawable.edittext_background);
}
if(roundedCorners){
if (state.equals(BOOTSTRAP_EDIT_TEXT_SUCCESS)){
this.setBackgroundResource(R.drawable.edittext_background_rounded_success);
} else if (state.equals(BOOTSTRAP_EDIT_TEXT_WARNING)){
this.setBackgroundResource(R.drawable.edittext_background_rounded_warning);
} else if (state.equals(BOOTSTRAP_EDIT_TEXT_DANGER)){
this.setBackgroundResource(R.drawable.edittext_background_rounded_danger);
}
} else {
if (state.equals(BOOTSTRAP_EDIT_TEXT_SUCCESS)){
this.setBackgroundResource(R.drawable.edittext_background_success);
} else if (state.equals(BOOTSTRAP_EDIT_TEXT_WARNING)){
this.setBackgroundResource(R.drawable.edittext_background_warning);
} else if (state.equals(BOOTSTRAP_EDIT_TEXT_DANGER)){
this.setBackgroundResource(R.drawable.edittext_background_danger);
}
}
}
/**
* Change the BootstrapEditTextState
* @param state
*/
public void setState(String state){
setBackgroundDrawable(state);
}
/**
* Set the BootstrapEditText to a successful state
*/
public void setSuccess()
{
setBackgroundDrawable(BOOTSTRAP_EDIT_TEXT_SUCCESS);
}
/**
* Set the BootstrapEditText to a warning state
*/
public void setWarning()
{
setBackgroundDrawable(BOOTSTRAP_EDIT_TEXT_WARNING);
}
/**
* Set the BootstrapEditText to a danger state
*/
public void setDanger()
{
setBackgroundDrawable(BOOTSTRAP_EDIT_TEXT_DANGER);
}
/**
* Set the BootstrapEditText to a default state
*/
public void setDefault()
{
setBackgroundDrawable(BOOTSTRAP_EDIT_TEXT_DEFAULT);
}
/**
* Specifies whether the BootstrapEditText is enabled or disabled
* @param enabled - boolean state for either enabled or disabled
*/
public void setBootstrapEditTextEnabled(boolean enabled)
{
this.setEnabled(enabled);
}
}

View File

@ -1,209 +0,0 @@
package com.beardedhen.androidbootstrap;
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
public class BootstrapThumbnail extends FrameLayout
{
private static final int DEFAULT_WIDTH = 150; //width of thumbnail when no width is given
private static final int DEFAULT_HEIGHT = 150;//height of thumbnail when no height is given
private static final int DEFAULT_MAX_PADDING = 8; //8dp is max padding size when padding isn't specified by user
private static final int DEFAULT_MIN_PADDING = 4; //4dp
private static final String DEFAULT_TYPE = "rounded";
private static Map<String, ThumbnailTypes> bThumbnailTypeMap;
private static Typeface font;
private ViewGroup container;
private LinearLayout placeholder;
private TextView dimensionsLabel;
private boolean roundedCorners = true;
static{
bThumbnailTypeMap = new HashMap<String, ThumbnailTypes>();
bThumbnailTypeMap.put("rounded", ThumbnailTypes.ROUNDED);//default is rounded if user doesn't specify to use square
bThumbnailTypeMap.put("square", ThumbnailTypes.SQUARE);
}
public BootstrapThumbnail(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
initialise(attrs);
}
public BootstrapThumbnail(Context context, AttributeSet attrs)
{
super(context, attrs);
initialise(attrs);
}
public BootstrapThumbnail(Context context)
{
super(context);
initialise(null);
}
public void setImage(int drawable)
{
this.placeholder.setBackgroundResource(drawable);
invalidate();
requestLayout();
}
//set up the bootstrap types
private enum ThumbnailTypes
{
ROUNDED(R.drawable.bthumbnail_container_rounded, R.drawable.bthumbnail_placeholder_default),
SQUARE(R.drawable.bthumbnail_container_square, R.drawable.bthumbnail_placeholder_default);
private int containerDrawable;
private int placeholderDrawable;
ThumbnailTypes(int containerDrawable, int placeholderDrawable)
{
this.containerDrawable = containerDrawable;
this.placeholderDrawable = placeholderDrawable;
}
}
private void initialise( AttributeSet attrs )
{
LayoutInflater inflator = (LayoutInflater)getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
readFont(getContext());
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.BootstrapThumbnail);
//defaults
ThumbnailTypes type = null;
String thumbnailType = DEFAULT_TYPE;
String text = "";
int imageDrawable = 0;
float scale = getResources().getDisplayMetrics().density; //for padding
int width = DEFAULT_WIDTH;
int height = DEFAULT_HEIGHT;
int padding = 0;
int paddingDP = 0;
//attribute values
if(a.getString(R.styleable.BootstrapThumbnail_bt_width) != null) {
width = (int) a.getDimension(R.styleable.BootstrapThumbnail_bt_width, 0);
Log.v("width", Integer.toString(width));
}
if(a.getString(R.styleable.BootstrapThumbnail_bt_height) != null) {
height = (int) a.getDimension(R.styleable.BootstrapThumbnail_bt_height, 0);
}
if(a.getString(R.styleable.BootstrapThumbnail_bt_inside_padding) != null) {
paddingDP = (int) a.getDimension(R.styleable.BootstrapThumbnail_bt_inside_padding, 0);
}
else{
padding = (int) (((Math.sqrt(width * height)) / 100) * 2);
if(padding > DEFAULT_MAX_PADDING)
padding = DEFAULT_MAX_PADDING;
if(padding < DEFAULT_MIN_PADDING)
padding = DEFAULT_MIN_PADDING;
paddingDP = (int) (padding * scale + 0.5f);//container padding in DP
}
if(a.getString(R.styleable.BootstrapThumbnail_bt_roundedCorners) != null){
roundedCorners = a.getBoolean(R.styleable.BootstrapThumbnail_bt_roundedCorners, false) ;
}
if(a.getString(R.styleable.BootstrapThumbnail_bt_image) != null){
imageDrawable = a.getResourceId(R.styleable.BootstrapThumbnail_bt_image, 0);
}
a.recycle();
text = (int)(width/scale) + "x" + (int)(height/scale);
View v = inflator.inflate(R.layout.bootstrap_thumbnail, null, false);
//get layout items
container = (ViewGroup) v.findViewById(R.id.container);
placeholder = (LinearLayout) v.findViewById(R.id.placeholder);
dimensionsLabel = (TextView) v.findViewById(R.id.dimensionsLabel);
Log.v("size", "width:" + width + " height:" + height);
type = bThumbnailTypeMap.get(thumbnailType);
//get the correct background type
if(roundedCorners == true)
{
type = bThumbnailTypeMap.get("rounded");
} else {
type = bThumbnailTypeMap.get("square");
}
//apply the background type
container.setBackgroundResource(type.containerDrawable);
//if no image is provided by user
if(imageDrawable == 0){
//set default grey placeholder background
placeholder.setBackgroundResource(type.placeholderDrawable);
//set the text
if(text.length() > 0){
dimensionsLabel.setText(text);
dimensionsLabel.setVisibility(View.VISIBLE);
}
}
else{
//set background to user's provided image
placeholder.setBackgroundResource(imageDrawable);
//remove textview dimensions
dimensionsLabel.setVisibility(View.GONE);
}
//placeholder padding
int paddingP = (int) (((Math.sqrt(width * height)) / 100) * 4);
//convert to DP
int paddingDPP = (int) (paddingP * scale + 0.5f);//placeholder padding in DP
container.setPadding(paddingDP, paddingDP, paddingDP, paddingDP);
placeholder.setPadding(paddingDPP, paddingDPP, paddingDPP, paddingDPP);
placeholder.setLayoutParams(new LinearLayout.LayoutParams(width,height));
//set the font awesome icon typeface
dimensionsLabel.setTypeface(font);
this.setClickable(true);
addView(v);
}
//static class to read in font
private static void readFont(Context context)
{
if(font == null){
try {
font = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
} catch (Exception e) {
Log.e("BootstrapButton", "Could not get typeface because " + e.getMessage());
font = Typeface.DEFAULT;
}
}
}
}

View File

@ -1,390 +0,0 @@
package com.beardedhen.androidbootstrap;
import java.util.HashMap;
import java.util.Map;
public class FontAwesome {
private static Map<String, String> faMap = new HashMap<String, String>();
//font awesome map as per
//http://fortawesome.github.io/Font-Awesome/cheatsheet/
static {
faMap.put("fa-glass", "\uf000");
faMap.put("fa-music", "\uf001");
faMap.put("fa-search", "\uf002");
faMap.put("fa-envelope-o", "\uf003");
faMap.put("fa-heart", "\uf004");
faMap.put("fa-star", "\uf005");
faMap.put("fa-star-o", "\uf006");
faMap.put("fa-user", "\uf007");
faMap.put("fa-film", "\uf008");
faMap.put("fa-th-large", "\uf009");
faMap.put("fa-th", "\uf00a");
faMap.put("fa-th-list", "\uf00b");
faMap.put("fa-check", "\uf00c");
faMap.put("fa-times", "\uf00d");
faMap.put("fa-search-plus", "\uf00e");
faMap.put("fa-search-minus", "\uf010");
faMap.put("fa-power-off", "\uf011");
faMap.put("fa-signal", "\uf012");
faMap.put("fa-cog", "\uf013");
faMap.put("fa-trash-o", "\uf014");
faMap.put("fa-home", "\uf015");
faMap.put("fa-file-o", "\uf016");
faMap.put("fa-clock-o", "\uf017");
faMap.put("fa-road", "\uf018");
faMap.put("fa-download", "\uf019");
faMap.put("fa-arrow-circle-o-down", "\uf01a");
faMap.put("fa-arrow-circle-o-up", "\uf01b");
faMap.put("fa-inbox", "\uf01c");
faMap.put("fa-play-circle-o", "\uf01d");
faMap.put("fa-repeat", "\uf01e");
faMap.put("fa-refresh", "\uf021");
faMap.put("fa-list-alt", "\uf022");
faMap.put("fa-lock", "\uf023");
faMap.put("fa-flag", "\uf024");
faMap.put("fa-headphones", "\uf025");
faMap.put("fa-volume-off", "\uf026");
faMap.put("fa-volume-down", "\uf027");
faMap.put("fa-volume-up", "\uf028");
faMap.put("fa-qrcode", "\uf029");
faMap.put("fa-barcode", "\uf02a");
faMap.put("fa-tag", "\uf02b");
faMap.put("fa-tags", "\uf02c");
faMap.put("fa-book", "\uf02d");
faMap.put("fa-bookmark", "\uf02e");
faMap.put("fa-print", "\uf02f");
faMap.put("fa-camera", "\uf030");
faMap.put("fa-font", "\uf031");
faMap.put("fa-bold", "\uf032");
faMap.put("fa-italic", "\uf033");
faMap.put("fa-text-height", "\uf034");
faMap.put("fa-text-width", "\uf035");
faMap.put("fa-align-left", "\uf036");
faMap.put("fa-align-center", "\uf037");
faMap.put("fa-align-right", "\uf038");
faMap.put("fa-align-justify", "\uf039");
faMap.put("fa-list", "\uf03a");
faMap.put("fa-outdent", "\uf03b");
faMap.put("fa-indent", "\uf03c");
faMap.put("fa-video-camera", "\uf03d");
faMap.put("fa-picture-o", "\uf03e");
faMap.put("fa-pencil", "\uf040");
faMap.put("fa-map-marker", "\uf041");
faMap.put("fa-adjust", "\uf042");
faMap.put("fa-tint", "\uf043");
faMap.put("fa-pencil-square-o", "\uf044");
faMap.put("fa-share-square-o", "\uf045");
faMap.put("fa-check-square-o", "\uf046");
faMap.put("fa-move", "\uf047");
faMap.put("fa-step-backward", "\uf048");
faMap.put("fa-fast-backward", "\uf049");
faMap.put("fa-backward", "\uf04a");
faMap.put("fa-play", "\uf04b");
faMap.put("fa-pause", "\uf04c");
faMap.put("fa-stop", "\uf04d");
faMap.put("fa-forward", "\uf04e");
faMap.put("fa-fast-forward", "\uf050");
faMap.put("fa-step-forward", "\uf051");
faMap.put("fa-eject", "\uf052");
faMap.put("fa-chevron-left", "\uf053");
faMap.put("fa-chevron-right", "\uf054");
faMap.put("fa-plus-circle", "\uf055");
faMap.put("fa-minus-circle", "\uf056");
faMap.put("fa-times-circle", "\uf057");
faMap.put("fa-check-circle", "\uf058");
faMap.put("fa-question-circle", "\uf059");
faMap.put("fa-info-circle", "\uf05a");
faMap.put("fa-crosshairs", "\uf05b");
faMap.put("fa-times-circle-o", "\uf05c");
faMap.put("fa-check-circle-o", "\uf05d");
faMap.put("fa-ban", "\uf05e");
faMap.put("fa-arrow-left", "\uf060");
faMap.put("fa-arrow-right", "\uf061");
faMap.put("fa-arrow-up", "\uf062");
faMap.put("fa-arrow-down", "\uf063");
faMap.put("fa-share", "\uf064");
faMap.put("fa-resize-full", "\uf065");
faMap.put("fa-resize-small", "\uf066");
faMap.put("fa-plus", "\uf067");
faMap.put("fa-minus", "\uf068");
faMap.put("fa-asterisk", "\uf069");
faMap.put("fa-exclamation-circle", "\uf06a");
faMap.put("fa-gift", "\uf06b");
faMap.put("fa-leaf", "\uf06c");
faMap.put("fa-fire", "\uf06d");
faMap.put("fa-eye", "\uf06e");
faMap.put("fa-eye-slash", "\uf070");
faMap.put("fa-exclamation-triangle", "\uf071");
faMap.put("fa-plane", "\uf072");
faMap.put("fa-calendar", "\uf073");
faMap.put("fa-random", "\uf074");
faMap.put("fa-comment", "\uf075");
faMap.put("fa-magnet", "\uf076");
faMap.put("fa-chevron-up", "\uf077");
faMap.put("fa-chevron-down", "\uf078");
faMap.put("fa-retweet", "\uf079");
faMap.put("fa-shopping-cart", "\uf07a");
faMap.put("fa-folder", "\uf07b");
faMap.put("fa-folder-open", "\uf07c");
faMap.put("fa-resize-vertical", "\uf07d");
faMap.put("fa-resize-horizontal", "\uf07e");
faMap.put("fa-bar-chart-o", "\uf080");
faMap.put("fa-twitter-square", "\uf081");
faMap.put("fa-facebook-square", "\uf082");
faMap.put("fa-camera-retro", "\uf083");
faMap.put("fa-key", "\uf084");
faMap.put("fa-cogs", "\uf085");
faMap.put("fa-comments", "\uf086");
faMap.put("fa-thumbs-o-up", "\uf087");
faMap.put("fa-thumbs-o-down", "\uf088");
faMap.put("fa-star-half", "\uf089");
faMap.put("fa-heart-o", "\uf08a");
faMap.put("fa-sign-out", "\uf08b");
faMap.put("fa-linkedin-square", "\uf08c");
faMap.put("fa-thumb-tack", "\uf08d");
faMap.put("fa-external-link", "\uf08e");
faMap.put("fa-sign-in", "\uf090");
faMap.put("fa-trophy", "\uf091");
faMap.put("fa-github-square", "\uf092");
faMap.put("fa-upload", "\uf093");
faMap.put("fa-lemon-o", "\uf094");
faMap.put("fa-phone", "\uf095");
faMap.put("fa-square-o", "\uf096");
faMap.put("fa-bookmark-o", "\uf097");
faMap.put("fa-phone-square", "\uf098");
faMap.put("fa-twitter", "\uf099");
faMap.put("fa-facebook", "\uf09a");
faMap.put("fa-github", "\uf09b");
faMap.put("fa-unlock", "\uf09c");
faMap.put("fa-credit-card", "\uf09d");
faMap.put("fa-rss", "\uf09e");
faMap.put("fa-hdd", "\uf0a0");
faMap.put("fa-bullhorn", "\uf0a1");
faMap.put("fa-bell", "\uf0f3");
faMap.put("fa-certificate", "\uf0a3");
faMap.put("fa-hand-o-right", "\uf0a4");
faMap.put("fa-hand-o-left", "\uf0a5");
faMap.put("fa-hand-o-up", "\uf0a6");
faMap.put("fa-hand-o-down", "\uf0a7");
faMap.put("fa-arrow-circle-left", "\uf0a8");
faMap.put("fa-arrow-circle-right", "\uf0a9");
faMap.put("fa-arrow-circle-up", "\uf0aa");
faMap.put("fa-arrow-circle-down", "\uf0ab");
faMap.put("fa-globe", "\uf0ac");
faMap.put("fa-wrench", "\uf0ad");
faMap.put("fa-tasks", "\uf0ae");
faMap.put("fa-filter", "\uf0b0");
faMap.put("fa-briefcase", "\uf0b1");
faMap.put("fa-fullscreen", "\uf0b2");
faMap.put("fa-group", "\uf0c0");
faMap.put("fa-link", "\uf0c1");
faMap.put("fa-cloud", "\uf0c2");
faMap.put("fa-flask", "\uf0c3");
faMap.put("fa-scissors", "\uf0c4");
faMap.put("fa-files-o", "\uf0c5");
faMap.put("fa-paperclip", "\uf0c6");
faMap.put("fa-floppy-o", "\uf0c7");
faMap.put("fa-square", "\uf0c8");
faMap.put("fa-reorder", "\uf0c9");
faMap.put("fa-list-ul", "\uf0ca");
faMap.put("fa-list-ol", "\uf0cb");
faMap.put("fa-strikethrough", "\uf0cc");
faMap.put("fa-underline", "\uf0cd");
faMap.put("fa-table", "\uf0ce");
faMap.put("fa-magic", "\uf0d0");
faMap.put("fa-truck", "\uf0d1");
faMap.put("fa-pinterest", "\uf0d2");
faMap.put("fa-pinterest-square", "\uf0d3");
faMap.put("fa-google-plus-square", "\uf0d4");
faMap.put("fa-google-plus", "\uf0d5");
faMap.put("fa-money", "\uf0d6");
faMap.put("fa-caret-down", "\uf0d7");
faMap.put("fa-caret-up", "\uf0d8");
faMap.put("fa-caret-left", "\uf0d9");
faMap.put("fa-caret-right", "\uf0da");
faMap.put("fa-columns", "\uf0db");
faMap.put("fa-sort", "\uf0dc");
faMap.put("fa-sort-asc", "\uf0dd");
faMap.put("fa-sort-desc", "\uf0de");
faMap.put("fa-envelope", "\uf0e0");
faMap.put("fa-linkedin", "\uf0e1");
faMap.put("fa-undo", "\uf0e2");
faMap.put("fa-gavel", "\uf0e3");
faMap.put("fa-tachometer", "\uf0e4");
faMap.put("fa-comment-o", "\uf0e5");
faMap.put("fa-comments-o", "\uf0e6");
faMap.put("fa-bolt", "\uf0e7");
faMap.put("fa-sitemap", "\uf0e8");
faMap.put("fa-umbrella", "\uf0e9");
faMap.put("fa-clipboard", "\uf0ea");
faMap.put("fa-lightbulb-o", "\uf0eb");
faMap.put("fa-exchange", "\uf0ec");
faMap.put("fa-cloud-download", "\uf0ed");
faMap.put("fa-cloud-upload", "\uf0ee");
faMap.put("fa-user-md", "\uf0f0");
faMap.put("fa-stethoscope", "\uf0f1");
faMap.put("fa-suitcase", "\uf0f2");
faMap.put("fa-bell-o", "\uf0a2");
faMap.put("fa-coffee", "\uf0f4");
faMap.put("fa-cutlery", "\uf0f5");
faMap.put("fa-file-text-o", "\uf0f6");
faMap.put("fa-building", "\uf0f7");
faMap.put("fa-hospital", "\uf0f8");
faMap.put("fa-ambulance", "\uf0f9");
faMap.put("fa-medkit", "\uf0fa");
faMap.put("fa-fighter-jet", "\uf0fb");
faMap.put("fa-beer", "\uf0fc");
faMap.put("fa-h-square", "\uf0fd");
faMap.put("fa-plus-square", "\uf0fe");
faMap.put("fa-angle-double-left", "\uf100");
faMap.put("fa-angle-double-right", "\uf101");
faMap.put("fa-angle-double-up", "\uf102");
faMap.put("fa-angle-double-down", "\uf103");
faMap.put("fa-angle-left", "\uf104");
faMap.put("fa-angle-right", "\uf105");
faMap.put("fa-angle-up", "\uf106");
faMap.put("fa-angle-down", "\uf107");
faMap.put("fa-desktop", "\uf108");
faMap.put("fa-laptop", "\uf109");
faMap.put("fa-tablet", "\uf10a");
faMap.put("fa-mobile", "\uf10b");
faMap.put("fa-circle-o", "\uf10c");
faMap.put("fa-quote-left", "\uf10d");
faMap.put("fa-quote-right", "\uf10e");
faMap.put("fa-spinner", "\uf110");
faMap.put("fa-circle", "\uf111");
faMap.put("fa-reply", "\uf112");
faMap.put("fa-github-alt", "\uf113");
faMap.put("fa-folder-o", "\uf114");
faMap.put("fa-folder-open-o", "\uf115");
faMap.put("fa-expand-o", "\uf116");
faMap.put("fa-collapse-o", "\uf117");
faMap.put("fa-smile-o", "\uf118");
faMap.put("fa-frown-o", "\uf119");
faMap.put("fa-meh-o", "\uf11a");
faMap.put("fa-gamepad", "\uf11b");
faMap.put("fa-keyboard-o", "\uf11c");
faMap.put("fa-flag-o", "\uf11d");
faMap.put("fa-flag-checkered", "\uf11e");
faMap.put("fa-terminal", "\uf120");
faMap.put("fa-code", "\uf121");
faMap.put("fa-reply-all", "\uf122");
faMap.put("fa-mail-reply-all", "\uf122");
faMap.put("fa-star-half-o", "\uf123");
faMap.put("fa-location-arrow", "\uf124");
faMap.put("fa-crop", "\uf125");
faMap.put("fa-code-fork", "\uf126");
faMap.put("fa-chain-broken", "\uf127");
faMap.put("fa-question", "\uf128");
faMap.put("fa-info", "\uf129");
faMap.put("fa-exclamation", "\uf12a");
faMap.put("fa-superscript", "\uf12b");
faMap.put("fa-subscript", "\uf12c");
faMap.put("fa-eraser", "\uf12d");
faMap.put("fa-puzzle-piece", "\uf12e");
faMap.put("fa-microphone", "\uf130");
faMap.put("fa-microphone-slash", "\uf131");
faMap.put("fa-shield", "\uf132");
faMap.put("fa-calendar-o", "\uf133");
faMap.put("fa-fire-extinguisher", "\uf134");
faMap.put("fa-rocket", "\uf135");
faMap.put("fa-maxcdn", "\uf136");
faMap.put("fa-chevron-circle-left", "\uf137");
faMap.put("fa-chevron-circle-right", "\uf138");
faMap.put("fa-chevron-circle-up", "\uf139");
faMap.put("fa-chevron-circle-down", "\uf13a");
faMap.put("fa-html5", "\uf13b");
faMap.put("fa-css3", "\uf13c");
faMap.put("fa-anchor", "\uf13d");
faMap.put("fa-unlock-o", "\uf13e");
faMap.put("fa-bullseye", "\uf140");
faMap.put("fa-ellipsis-horizontal", "\uf141");
faMap.put("fa-ellipsis-vertical", "\uf142");
faMap.put("fa-rss-square", "\uf143");
faMap.put("fa-play-circle", "\uf144");
faMap.put("fa-ticket", "\uf145");
faMap.put("fa-minus-square", "\uf146");
faMap.put("fa-minus-square-o", "\uf147");
faMap.put("fa-level-up", "\uf148");
faMap.put("fa-level-down", "\uf149");
faMap.put("fa-check-square", "\uf14a");
faMap.put("fa-pencil-square", "\uf14b");
faMap.put("fa-external-link-square", "\uf14c");
faMap.put("fa-share-square", "\uf14d");
faMap.put("fa-compass", "\uf14e");
faMap.put("fa-caret-square-o-down", "\uf150");
faMap.put("fa-caret-square-o-up", "\uf151");
faMap.put("fa-caret-square-o-right", "\uf152");
faMap.put("fa-eur", "\uf153");
faMap.put("fa-gbp", "\uf154");
faMap.put("fa-usd", "\uf155");
faMap.put("fa-inr", "\uf156");
faMap.put("fa-jpy", "\uf157");
faMap.put("fa-rub", "\uf158");
faMap.put("fa-krw", "\uf159");
faMap.put("fa-btc", "\uf15a");
faMap.put("fa-file", "\uf15b");
faMap.put("fa-file-text", "\uf15c");
faMap.put("fa-sort-alpha-asc", "\uf15d");
faMap.put("fa-sort-alpha-desc", "\uf15e");
faMap.put("fa-sort-amount-asc", "\uf160");
faMap.put("fa-sort-amount-desc", "\uf161");
faMap.put("fa-sort-numeric-asc", "\uf162");
faMap.put("fa-sort-numeric-desc", "\uf163");
faMap.put("fa-thumbs-up", "\uf164");
faMap.put("fa-thumbs-down", "\uf165");
faMap.put("fa-youtube-square", "\uf166");
faMap.put("fa-youtube", "\uf167");
faMap.put("fa-xing", "\uf168");
faMap.put("fa-xing-square", "\uf169");
faMap.put("fa-youtube-play", "\uf16a");
faMap.put("fa-dropbox", "\uf16b");
faMap.put("fa-stack-overflow", "\uf16c");
faMap.put("fa-instagram", "\uf16d");
faMap.put("fa-flickr", "\uf16e");
faMap.put("fa-adn", "\uf170");
faMap.put("fa-bitbucket", "\uf171");
faMap.put("fa-bitbucket-square", "\uf172");
faMap.put("fa-tumblr", "\uf173");
faMap.put("fa-tumblr-square", "\uf174");
faMap.put("fa-long-arrow-down", "\uf175");
faMap.put("fa-long-arrow-up", "\uf176");
faMap.put("fa-long-arrow-left", "\uf177");
faMap.put("fa-long-arrow-right", "\uf178");
faMap.put("fa-apple", "\uf179");
faMap.put("fa-windows", "\uf17a");
faMap.put("fa-android", "\uf17b");
faMap.put("fa-linux", "\uf17c");
faMap.put("fa-dribbble", "\uf17d");
faMap.put("fa-skype", "\uf17e");
faMap.put("fa-foursquare", "\uf180");
faMap.put("fa-trello", "\uf181");
faMap.put("fa-female", "\uf182");
faMap.put("fa-male", "\uf183");
faMap.put("fa-gittip", "\uf184");
faMap.put("fa-sun-o", "\uf185");
faMap.put("fa-moon-o", "\uf186");
faMap.put("fa-archive", "\uf187");
faMap.put("fa-bug", "\uf188");
faMap.put("fa-vk", "\uf189");
faMap.put("fa-weibo", "\uf18a");
faMap.put("fa-renren", "\uf18b");
faMap.put("fa-pagelines", "\uf18c");
faMap.put("fa-stack-exchange", "\uf18d");
faMap.put("fa-arrow-circle-o-right", "\uf18e");
faMap.put("fa-arrow-circle-o-left", "\uf190");
faMap.put("fa-caret-square-o-left", "\uf191");
faMap.put("fa-dot-circle-o", "\uf192");
faMap.put("fa-wheelchair", "\uf193");
faMap.put("fa-vimeo-square", "\uf194");
}
public static Map<String, String> getFaMap()
{
return faMap;
}
}

View File

@ -1,274 +0,0 @@
package com.beardedhen.androidbootstrap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.beardedhen.androidbootstrap.R;
public class FontAwesomeText extends FrameLayout {
private static Typeface font;
private static Map<String, String> faMap;
private TextView tv;
private static final String FA_ICON_QUESTION = "fa-question";
public enum AnimationSpeed
{
FAST,
MEDIUM,
SLOW;
}
static{
faMap = FontAwesome.getFaMap();
}
public FontAwesomeText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialise(attrs);
}
public FontAwesomeText(Context context, AttributeSet attrs) {
super(context, attrs);
initialise(attrs);
}
public FontAwesomeText(Context context) {
super(context);
initialise(null);
}
private void initialise( AttributeSet attrs )
{
LayoutInflater inflator = (LayoutInflater)getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
//get font
readFont(getContext());
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.FontAwesomeText);
//inflate the view
View fontAwesomeTextView = inflator.inflate(R.layout.font_awesome_text, null, false);
tv = (TextView)fontAwesomeTextView.findViewById(R.id.lblText);
String icon = "";
float fontSize = 14.0f;
//icon
if (a.getString(R.styleable.FontAwesomeText_fa_icon) != null) {
icon = a.getString(R.styleable.FontAwesomeText_fa_icon);
}
//font size
if (a.getString(R.styleable.FontAwesomeText_android_textSize) != null) {
String xmlProvidedSize = attrs.getAttributeValue(
"http://schemas.android.com/apk/res/android", "textSize");
final Pattern PATTERN_FONT_SIZE = Pattern
.compile("([0-9]+[.]?[0-9]*)sp");
Matcher m = PATTERN_FONT_SIZE.matcher(xmlProvidedSize);
if (m.find()) {
if (m.groupCount() == 1) {
fontSize = Float.valueOf(m.group(1));
}
}
}
//text colour
if(a.getString(R.styleable.FontAwesomeText_android_textColor) != null){
tv.setTextColor(a.getColor(R.styleable.FontAwesomeText_android_textColor, R.color.bbutton_inverse));
}
setIcon(icon);
tv.setTypeface(font);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
a.recycle();
addView(fontAwesomeTextView);
}
private static void readFont(Context context)
{
if(font == null){
try {
font = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
} catch (Exception e) {
Log.e("BButton", "Could not get typeface because " + e.getMessage());
font = Typeface.DEFAULT;
}
}
}
/**
* Used to start flashing a FontAwesomeText item
* @param context the current applications context
* @param forever whether the item should flash repeatedly or just once
* @param speed how fast the item should flash, chose between FontAwesomeText.AnimationSpeed.SLOW /
* FontAwesomeText.AnimationSpeed.MEDIUM / FontAwesomeText.AnimationSpeed.FAST
*/
public void startFlashing(Context context, boolean forever, AnimationSpeed speed)
{
Animation fadeIn = new AlphaAnimation(0, 1);
//set up extra variables
fadeIn.setDuration(50);
fadeIn.setRepeatMode(Animation.REVERSE);
//default repeat count is 0, however if user wants, set it up to be infinite
fadeIn.setRepeatCount(0);
if (forever){
fadeIn.setRepeatCount(Animation.INFINITE);
}
//default speed
fadeIn.setStartOffset(1000);
//fast
if (speed.equals(AnimationSpeed.FAST))
{
fadeIn.setStartOffset(200);
}
//medium
if (speed.equals(AnimationSpeed.MEDIUM))
{
fadeIn.setStartOffset(500);
}
//set the new animation to a final animation
final Animation animation = fadeIn;
//run the animation - used to work correctly on older devices
tv.postDelayed(new Runnable() {
@Override
public void run() {
tv.startAnimation(animation);
}
}, 100);
}
/**
* Used to start rotating a FontAwesomeText item
* @param context the current applications context
* @param clockwise true for clockwise, false for anti clockwise spinning
* @param speed how fast the item should flash, chose between FontAwesomeText.AnimationSpeed.SLOW /
* FontAwesomeText.AnimationSpeed.MEDIUM / FontAwesomeText.AnimationSpeed.FAST
*/
public void startRotate(Context context, boolean clockwise, AnimationSpeed speed)
{
Animation rotate;
//set up the rotation animation
if (clockwise){
rotate = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);
} else {
rotate = new RotateAnimation(360, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);
}
//set up some extra variables
rotate.setRepeatCount(Animation.INFINITE);
rotate.setInterpolator(new LinearInterpolator());
rotate.setStartOffset(0);
rotate.setRepeatMode(Animation.RESTART);
//defaults
rotate.setDuration(2000);
//fast
if (speed.equals(AnimationSpeed.FAST))
{
rotate.setDuration(500);
}
//medium
if (speed.equals(AnimationSpeed.MEDIUM))
{
rotate.setDuration(1000);
}
//send the new animation to a final animation
final Animation animation = rotate;
//run the animation - used to work correctly on older devices
tv.postDelayed(new Runnable() {
@Override
public void run() {
tv.startAnimation(animation);
}
}, 100);
}
/**
* Used to stop animating any FontAwesomeText item
*/
public void stopAnimation(){
//stop the animation
tv.clearAnimation();
}
/**
* Used to set the icon for a FontAwesomeText item
* @param faIcon - String value for the icon as per http://fortawesome.github.io/Font-Awesome/cheatsheet/
*/
public void setIcon(String faIcon) {
String icon = faMap.get(faIcon);
if (icon == null)
{
icon = faMap.get(FA_ICON_QUESTION);
}
tv.setText(icon);
}
/**
* Used to set the text color of the underlying text view.
* @param color - Integer value representing a color resource.
*/
public void setTextColor(int color) {
tv.setTextColor(color);
}
/**
* Used to set the text size of the underlying text view.
* @param unit - Integer value representing a unit size
* @param size - Float value representing text size
*/
public void setTextSize(int unit, float size) {
tv.setTextSize(unit, size);
}
}

View File

@ -1,303 +0,0 @@
package com.beardedhen.androidbootstrap.utils;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.RectF;
import android.os.Build;
import android.text.Layout.Alignment;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.widget.TextView;
/**
*
* Code from user M-WaJeEh on StackOverflow at
* http://stackoverflow.com/questions/5033012/auto-scale-textview-text-to-fit-within-bounds/17782522#17782522
*
*/
public class AutoResizeTextView extends TextView {
private interface SizeTester {
/**
*
* @param suggestedSize
* Size of text to be tested
* @param availableSpace
* available space in which text must fit
* @return an integer < 0 if after applying {@code suggestedSize} to
* text, it takes less space than {@code availableSpace}, > 0
* otherwise
*/
public int onTestSize(int suggestedSize, RectF availableSpace);
}
private RectF mTextRect = new RectF();
private RectF mAvailableSpaceRect;
private SparseIntArray mTextCachedSizes;
private TextPaint mPaint;
private float mMaxTextSize;
private float mSpacingMult = 1.0f;
private float mSpacingAdd = 0.0f;
private float mMinTextSize = 20;
private int mWidthLimit;
private static final int NO_LINE_LIMIT = -1;
private int mMaxLines;
private boolean mEnableSizeCache = true;
private boolean mInitiallized;
public AutoResizeTextView(Context context) {
super(context);
initialize();
}
public AutoResizeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialize();
}
private void initialize() {
mPaint = new TextPaint(getPaint());
mMaxTextSize = getTextSize();
mAvailableSpaceRect = new RectF();
mTextCachedSizes = new SparseIntArray();
if (mMaxLines == 0) {
// no value was assigned during construction
mMaxLines = NO_LINE_LIMIT;
}
mInitiallized = true;
}
@Override
public void setText(final CharSequence text, BufferType type) {
super.setText(text, type);
adjustTextSize(text.toString());
}
@Override
public void setTextSize(float size) {
mMaxTextSize = size;
mTextCachedSizes.clear();
adjustTextSize(getText().toString());
}
@Override
public void setMaxLines(int maxlines) {
super.setMaxLines(maxlines);
mMaxLines = maxlines;
reAdjust();
}
public int getMaxLines() {
return mMaxLines;
}
@Override
public void setSingleLine() {
super.setSingleLine();
mMaxLines = 1;
reAdjust();
}
@Override
public void setSingleLine(boolean singleLine) {
super.setSingleLine(singleLine);
if (singleLine) {
mMaxLines = 1;
} else {
mMaxLines = NO_LINE_LIMIT;
}
reAdjust();
}
@Override
public void setLines(int lines) {
super.setLines(lines);
mMaxLines = lines;
reAdjust();
}
@Override
public void setTextSize(int unit, float size) {
Context c = getContext();
Resources r;
if (c == null)
r = Resources.getSystem();
else
r = c.getResources();
mMaxTextSize = TypedValue.applyDimension(unit, size,
r.getDisplayMetrics());
mTextCachedSizes.clear();
adjustTextSize(getText().toString());
}
@Override
public void setLineSpacing(float add, float mult) {
super.setLineSpacing(add, mult);
mSpacingMult = mult;
mSpacingAdd = add;
}
/**
* Set the lower text size limit and invalidate the view
*
* @param minTextSize
*/
public void setMinTextSize(float minTextSize) {
mMinTextSize = minTextSize;
reAdjust();
}
private void reAdjust() {
adjustTextSize(getText().toString());
}
private void adjustTextSize(String string) {
if (!mInitiallized) {
return;
}
int startSize = (int) mMinTextSize;
int heightLimit = getMeasuredHeight() - getCompoundPaddingBottom()
- getCompoundPaddingTop();
mWidthLimit = getMeasuredWidth() - getCompoundPaddingLeft()
- getCompoundPaddingRight();
mAvailableSpaceRect.right = mWidthLimit;
mAvailableSpaceRect.bottom = heightLimit;
super.setTextSize(
TypedValue.COMPLEX_UNIT_PX,
efficientTextSizeSearch(startSize, (int) mMaxTextSize,
mSizeTester, mAvailableSpaceRect));
}
private final SizeTester mSizeTester = new SizeTester() {
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public int onTestSize(int suggestedSize, RectF availableSPace) {
mPaint.setTextSize(suggestedSize);
String text = getText().toString();
boolean singleline = getMaxLines() == 1;
if (singleline) {
mTextRect.bottom = mPaint.getFontSpacing();
mTextRect.right = mPaint.measureText(text);
} else {
StaticLayout layout = new StaticLayout(text, mPaint,
mWidthLimit, Alignment.ALIGN_NORMAL, mSpacingMult,
mSpacingAdd, true);
// return early if we have more lines
if (getMaxLines() != NO_LINE_LIMIT
&& layout.getLineCount() > getMaxLines()) {
return 1;
}
mTextRect.bottom = layout.getHeight();
int maxWidth = -1;
for (int i = 0; i < layout.getLineCount(); i++) {
if (maxWidth < layout.getLineWidth(i)) {
maxWidth = (int) layout.getLineWidth(i);
}
}
mTextRect.right = maxWidth;
}
mTextRect.offsetTo(0, 0);
if (availableSPace.contains(mTextRect)) {
// may be too small, don't worry we will find the best match
return -1;
} else {
// too big
return 1;
}
}
};
/**
* Enables or disables size caching, enabling it will improve performance
* where you are animating a value inside TextView. This stores the font
* size against getText().length() Be careful though while enabling it as 0
* takes more space than 1 on some fonts and so on.
*
* @param enable
* enable font size caching
*/
public void enableSizeCache(boolean enable) {
mEnableSizeCache = enable;
mTextCachedSizes.clear();
adjustTextSize(getText().toString());
}
private int efficientTextSizeSearch(int start, int end,
SizeTester sizeTester, RectF availableSpace) {
if (!mEnableSizeCache) {
return binarySearch(start, end, sizeTester, availableSpace);
}
String text = getText().toString();
int key = text == null ? 0 : text.length();
int size = mTextCachedSizes.get(key);
if (size != 0) {
return size;
}
size = binarySearch(start, end, sizeTester, availableSpace);
mTextCachedSizes.put(key, size);
return size;
}
private static int binarySearch(int start, int end, SizeTester sizeTester,
RectF availableSpace) {
int lastBest = start;
int lo = start;
int hi = end - 1;
int mid = 0;
while (lo <= hi) {
mid = (lo + hi) >>> 1;
int midValCmp = sizeTester.onTestSize(mid, availableSpace);
if (midValCmp < 0) {
lastBest = lo;
lo = mid + 1;
} else if (midValCmp > 0) {
hi = mid - 1;
lastBest = hi;
} else {
return mid;
}
}
// make sure to return last best
// this is what should always be returned
return lastBest;
}
@Override
protected void onTextChanged(final CharSequence text, final int start,
final int before, final int after) {
super.onTextChanged(text, start, before, after);
reAdjust();
}
@Override
protected void onSizeChanged(int width, int height, int oldwidth,
int oldheight) {
mTextCachedSizes.clear();
super.onSizeChanged(width, height, oldwidth, oldheight);
if (width != oldwidth || height != oldheight) {
reAdjust();
}
}
}

View File

@ -1,77 +0,0 @@
package com.beardedhen.androidbootstrap.utils;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
public class ImageUtils
{
public static Bitmap getCircleBitmap(Bitmap bitmap)
{
return getCircleBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight());
}
public static Bitmap getCircleBitmap(Bitmap bitmap, int width, int height)
{
Bitmap croppedBitmap = scaleCenterCrop(bitmap, width, height);
Bitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, width, height);
final RectF rectF = new RectF(rect);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
int radius = 0;
if(width > height)
{
radius = height / 2;
}
else
{
radius = width / 2;
}
canvas.drawCircle(width / 2, height / 2, radius, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(croppedBitmap, rect, rect, paint);
return output;
}
public static Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth)
{
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
float xScale = (float) newWidth / sourceWidth;
float yScale = (float) newHeight / sourceHeight;
float scale = Math.max(xScale, yScale);
float scaledWidth = scale * sourceWidth;
float scaledHeight = scale * sourceHeight;
float left = (newWidth - scaledWidth) / 2;
float top = (newHeight - scaledHeight) / 2;
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
Canvas canvas = new Canvas(dest);
canvas.drawBitmap(source, null, targetRect, null);
return dest;
}
}

View File

@ -1,30 +0,0 @@
#Android specific
bin
gen
obj
libs/armeabi
lint.xml
local.properties
release.properties
ant.properties
*.class
*.apk
#Gradle
.gradle
build
gradle.properties
#Maven
target
pom.xml.*
#Eclipse
.project
.classpath
.settings
.metadata
#IntelliJ IDEA
.idea
*.iml

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.sufficientlysecure.htmltextview"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="17"/>
<application/>
</manifest>

View File

@ -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.

View File

@ -1,45 +0,0 @@
# HtmlTextView for Android
This HtmlTextView supports all HTML tags supported by Android's Html class (see [The CommonsBlog](http://commonsware.com/blog/Android/2010/05/26/html-tags-supported-by-textview.html) and [history of Html class](https://github.com/android/platform_frameworks_base/commits/master/core/java/android/text/Html.java) for newer additions).
Additionally, list tags are supported (``<ul>``, ``<ol>``, ``<dd>``) and code tags with ``<code>``.
This also includes a workaround to prevent TextView crashing on [specific Android versions](http://code.google.com/p/android/issues/detail?id=35466).
This library is kept very tiny with no external dependencies.
I am using it to provide Help/About Activities in my apps.
## Example
```
HtmlTextView text = new HtmlTextView(this);
// loads html from string
text.setHtmlFromString("<b>Hello</b><ul><li>world</li><li>cats</li></ul>");
```
or
```
HtmlTextView text = new HtmlTextView(this);
// loads html from raw resource, i.e., a html file in res/raw/, this allows translatable resource (e.g., res/raw-de/ for german)
text.setHtmlFromRawResource(this, R.raw.help);
```
## Use library as Gradle dependency (Android library project)
1. Copy this folder to your project and include it in ``settings.gradle`` with ``include ':html-textview'``
2. Add dependency ``compile project(':html-textview')`` to your project's ``build.gradle``.
## License
Apache License v2
## Authors
- This library was hacked together by Dominik Schürmann
- Original [TagHandler](https://gist.github.com/mlakkadshaw/5983704) developed by [Mohammed Lakkadshaw](http://blog.mohammedlakkadshaw.com/)
- Original [UrlImageGetter](https://gist.github.com/Antarix/4167655) developed by Antarix Tandon
- [JellyBeanSpanFixTextView](https://gist.github.com/pyricau/3424004) (with fix from comment) developed by Pierre-Yves Ricau
## Contributions
Feel free to fork and do pull requests. I am more than happy to merge them.
Please do not introduce external dependencies.

View File

@ -1,20 +0,0 @@
apply plugin: 'android-library'
android {
compileSdkVersion 19
buildToolsVersion '19.0.3'
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
res.srcDirs = ['res']
}
}
// Do not abort build if lint finds errors
lintOptions {
abortOnError false
}
}

View File

@ -1,92 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="HtmlTextView" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@ -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 *;
#}

View File

@ -1,15 +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-19
android.library=true

View File

@ -1,92 +0,0 @@
/*
* Copyright (C) 2013 Mohammed Lakkadshaw
*
* 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 org.sufficientlysecure.htmltextview;
import java.util.Vector;
import org.xml.sax.XMLReader;
import android.text.Editable;
import android.text.Html;
import android.text.Spannable;
import android.text.style.BulletSpan;
import android.text.style.LeadingMarginSpan;
import android.text.style.TypefaceSpan;
import android.util.Log;
public class HtmlTagHandler implements Html.TagHandler {
private int mListItemCount = 0;
private Vector<String> mListParents = new Vector<String>();
@Override
public void handleTag(final boolean opening, final String tag, Editable output, final XMLReader xmlReader) {
if (tag.equals("ul") || tag.equals("ol") || tag.equals("dd")) {
if (opening) {
mListParents.add(tag);
} else mListParents.remove(tag);
mListItemCount = 0;
} else if (tag.equals("li") && !opening) {
handleListTag(output);
} else if (tag.equalsIgnoreCase("code")) {
if (opening) {
output.setSpan(new TypefaceSpan("monospace"), output.length(), output.length(), Spannable.SPAN_MARK_MARK);
} else {
Log.d(HtmlTextView.TAG, "Code tag encountered");
Object obj = getLast(output, TypefaceSpan.class);
int where = output.getSpanStart(obj);
output.setSpan(new TypefaceSpan("monospace"), where, output.length(), 0);
}
}
}
private Object getLast(Editable text, Class kind) {
Object[] objs = text.getSpans(0, text.length(), kind);
if (objs.length == 0) {
return null;
} else {
for (int i = objs.length; i > 0; i--) {
if (text.getSpanFlags(objs[i - 1]) == Spannable.SPAN_MARK_MARK) {
return objs[i - 1];
}
}
return null;
}
}
private void handleListTag(Editable output) {
if (mListParents.lastElement().equals("ul")) {
output.append("\n");
String[] split = output.toString().split("\n");
int lastIndex = split.length - 1;
int start = output.length() - split[lastIndex].length() - 1;
output.setSpan(new BulletSpan(15 * mListParents.size()), start, output.length(), 0);
} else if (mListParents.lastElement().equals("ol")) {
mListItemCount++;
output.append("\n");
String[] split = output.toString().split("\n");
int lastIndex = split.length - 1;
int start = output.length() - split[lastIndex].length() - 1;
output.insert(start, mListItemCount + ". ");
output.setSpan(new LeadingMarginSpan.Standard(15 * mListParents.size()), start, output.length(), 0);
}
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
*
* 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 org.sufficientlysecure.htmltextview;
import android.content.Context;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.AttributeSet;
import java.io.InputStream;
public class HtmlTextView extends JellyBeanSpanFixTextView {
public static final String TAG = "HtmlTextView";
public HtmlTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public HtmlTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HtmlTextView(Context context) {
super(context);
}
/**
* http://stackoverflow.com/questions/309424/read-convert-an-inputstream-to-a-string
*
* @param is
* @return
*/
static private String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
/**
* Loads HTML from a raw resource, i.e., a HTML file in res/raw/.
* This allows translatable resource (e.g., res/raw-de/ for german).
* The containing HTML is parsed to Android's Spannable format and then displayed.
*
* @param context
* @param id for example: R.raw.help
*/
public void setHtmlFromRawResource(Context context, int id) {
// load html from html file from /res/raw
InputStream inputStreamText = context.getResources().openRawResource(id);
setHtmlFromString(convertStreamToString(inputStreamText));
}
/**
* Parses String containing HTML to Android's Spannable format and displays it in this TextView.
*
* @param html String containing HTML, for example: "<b>Hello world!</b>"
*/
public void setHtmlFromString(String html) {
// this uses Android's Html class for basic parsing, and HtmlTagHandler
setText(Html.fromHtml(html, new UrlImageGetter(this, getContext()), new HtmlTagHandler()));
// make links work
setMovementMethod(LinkMovementMethod.getInstance());
// no flickering when clicking textview for Android < 4
// text.setTextColor(getResources().getColor(android.R.color.secondary_text_dark_nodisable));
}
}

View File

@ -1,212 +0,0 @@
/*
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2012 Pierre-Yves Ricau <py.ricau@gmail.com>
*
* 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 org.sufficientlysecure.htmltextview;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
/**
* <p>
* A {@link android.widget.TextView} that insert spaces around its text spans where needed to prevent
* {@link IndexOutOfBoundsException} in {@link #onMeasure(int, int)} on Jelly Bean.
* <p>
* When {@link #onMeasure(int, int)} throws an exception, we try to fix the text by adding spaces
* around spans, until it works again. We then try removing some of the added spans, to minimize the
* insertions.
* <p>
* The fix is time consuming (a few ms, it depends on the size of your text), but it should only
* happen once per text change.
* <p>
* See http://code.google.com/p/android/issues/detail?id=35466
*
*/
public class JellyBeanSpanFixTextView extends TextView {
private static class FixingResult {
public final boolean fixed;
public final List<Object> spansWithSpacesBefore;
public final List<Object> spansWithSpacesAfter;
public static FixingResult fixed(List<Object> spansWithSpacesBefore,
List<Object> spansWithSpacesAfter) {
return new FixingResult(true, spansWithSpacesBefore, spansWithSpacesAfter);
}
public static FixingResult notFixed() {
return new FixingResult(false, null, null);
}
private FixingResult(boolean fixed, List<Object> spansWithSpacesBefore,
List<Object> spansWithSpacesAfter) {
this.fixed = fixed;
this.spansWithSpacesBefore = spansWithSpacesBefore;
this.spansWithSpacesAfter = spansWithSpacesAfter;
}
}
public JellyBeanSpanFixTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public JellyBeanSpanFixTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public JellyBeanSpanFixTextView(Context context) {
super(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} catch (IndexOutOfBoundsException e) {
fixOnMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
/**
* If possible, fixes the Spanned text by adding spaces around spans when needed.
*/
private void fixOnMeasure(int widthMeasureSpec, int heightMeasureSpec) {
CharSequence text = getText();
if (text instanceof Spanned) {
SpannableStringBuilder builder = new SpannableStringBuilder(text);
fixSpannedWithSpaces(builder, widthMeasureSpec, heightMeasureSpec);
} else {
if (BuildConfig.DEBUG) {
Log.d(HtmlTextView.TAG, "The text isn't a Spanned");
}
fallbackToString(widthMeasureSpec, heightMeasureSpec);
}
}
/**
* Add spaces around spans until the text is fixed, and then removes the unneeded spaces
*/
private void fixSpannedWithSpaces(SpannableStringBuilder builder, int widthMeasureSpec,
int heightMeasureSpec) {
long startFix = System.currentTimeMillis();
FixingResult result = addSpacesAroundSpansUntilFixed(builder, widthMeasureSpec,
heightMeasureSpec);
if (result.fixed) {
removeUnneededSpaces(widthMeasureSpec, heightMeasureSpec, builder, result);
} else {
fallbackToString(widthMeasureSpec, heightMeasureSpec);
}
if (BuildConfig.DEBUG) {
long fixDuration = System.currentTimeMillis() - startFix;
Log.d(HtmlTextView.TAG, "fixSpannedWithSpaces() duration in ms: " + fixDuration);
}
}
private FixingResult addSpacesAroundSpansUntilFixed(SpannableStringBuilder builder,
int widthMeasureSpec, int heightMeasureSpec) {
Object[] spans = builder.getSpans(0, builder.length(), Object.class);
List<Object> spansWithSpacesBefore = new ArrayList<Object>(spans.length);
List<Object> spansWithSpacesAfter = new ArrayList<Object>(spans.length);
for (Object span : spans) {
int spanStart = builder.getSpanStart(span);
if (isNotSpace(builder, spanStart - 1)) {
builder.insert(spanStart, " ");
spansWithSpacesBefore.add(span);
}
int spanEnd = builder.getSpanEnd(span);
if (isNotSpace(builder, spanEnd)) {
builder.insert(spanEnd, " ");
spansWithSpacesAfter.add(span);
}
try {
setTextAndMeasure(builder, widthMeasureSpec, heightMeasureSpec);
return FixingResult.fixed(spansWithSpacesBefore, spansWithSpacesAfter);
} catch (IndexOutOfBoundsException notFixed) {
}
}
if (BuildConfig.DEBUG) {
Log.d(HtmlTextView.TAG, "Could not fix the Spanned by adding spaces around spans");
}
return FixingResult.notFixed();
}
private boolean isNotSpace(CharSequence text, int where) {
if (where < 0)
return true;
return text.charAt(where) != ' ';
}
private void setTextAndMeasure(CharSequence text, int widthMeasureSpec, int heightMeasureSpec) {
setText(text);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void removeUnneededSpaces(int widthMeasureSpec, int heightMeasureSpec,
SpannableStringBuilder builder, FixingResult result) {
for (Object span : result.spansWithSpacesAfter) {
int spanEnd = builder.getSpanEnd(span);
builder.delete(spanEnd, spanEnd + 1);
try {
setTextAndMeasure(builder, widthMeasureSpec, heightMeasureSpec);
} catch (IndexOutOfBoundsException ignored) {
builder.insert(spanEnd, " ");
}
}
boolean needReset = true;
for (Object span : result.spansWithSpacesBefore) {
int spanStart = builder.getSpanStart(span);
builder.delete(spanStart - 1, spanStart);
try {
setTextAndMeasure(builder, widthMeasureSpec, heightMeasureSpec);
needReset = false;
} catch (IndexOutOfBoundsException ignored) {
needReset = true;
int newSpanStart = spanStart - 1;
builder.insert(newSpanStart, " ");
}
}
if (needReset) {
setText(builder);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
private void fallbackToString(int widthMeasureSpec, int heightMeasureSpec) {
if (BuildConfig.DEBUG) {
Log.d(HtmlTextView.TAG, "Fallback to unspanned text");
}
String fallbackText = getText().toString();
setTextAndMeasure(fallbackText, widthMeasureSpec, heightMeasureSpec);
}
}

View File

@ -1,128 +0,0 @@
/*
* Copyright (C) 2013 Antarix Tandon
*
* 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 org.sufficientlysecure.htmltextview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.text.Html.ImageGetter;
import android.view.View;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
public class UrlImageGetter implements ImageGetter {
Context c;
View container;
/**
* Construct the URLImageParser which will execute AsyncTask and refresh the container
*
* @param t
* @param c
*/
public UrlImageGetter(View t, Context c) {
this.c = c;
this.container = t;
}
public Drawable getDrawable(String source) {
UrlDrawable urlDrawable = new UrlDrawable();
// get the actual source
ImageGetterAsyncTask asyncTask = new ImageGetterAsyncTask(urlDrawable);
asyncTask.execute(source);
// return reference to URLDrawable where I will change with actual image from
// the src tag
return urlDrawable;
}
public class ImageGetterAsyncTask extends AsyncTask<String, Void, Drawable> {
UrlDrawable urlDrawable;
public ImageGetterAsyncTask(UrlDrawable d) {
this.urlDrawable = d;
}
@Override
protected Drawable doInBackground(String... params) {
String source = params[0];
return fetchDrawable(source);
}
@Override
protected void onPostExecute(Drawable result) {
// set the correct bound according to the result from HTTP call
urlDrawable.setBounds(0, 0, 0 + result.getIntrinsicWidth(), 0 + result.getIntrinsicHeight());
// change the reference of the current drawable to the result
// from the HTTP call
urlDrawable.drawable = result;
// redraw the image by invalidating the container
UrlImageGetter.this.container.invalidate();
}
/**
* Get the Drawable from URL
*
* @param urlString
* @return
*/
public Drawable fetchDrawable(String urlString) {
try {
InputStream is = fetch(urlString);
Drawable drawable = Drawable.createFromStream(is, "src");
drawable.setBounds(0, 0, 0 + drawable.getIntrinsicWidth(), 0 + drawable.getIntrinsicHeight());
return drawable;
} catch (Exception e) {
return null;
}
}
private InputStream fetch(String urlString) throws MalformedURLException, IOException {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(urlString);
HttpResponse response = httpClient.execute(request);
return response.getEntity().getContent();
}
}
@SuppressWarnings("deprecation")
public class UrlDrawable extends BitmapDrawable {
// the drawable that you need to set, you could set the initial drawing
// with the loading image if you need to
protected Drawable drawable;
@Override
public void draw(Canvas canvas) {
// override the draw to facilitate refresh function later
if (drawable != null) {
drawable.draw(canvas);
}
}
}
}

View File

@ -1,98 +0,0 @@
###Android###
# built application files
*.apk
*.ap_
# files for the dex VM
*.dex
# Java class files
*.class
# generated files
bin/
gen/
# Local configuration file (sdk path, etc)
local.properties
# Eclipse project files
.classpath
.project
###Eclipse###
*.pydevproject
.project
.metadata
bin/**
tmp/**
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
###Maven###
target/
###Gradle###
.gradle/
build/
###IntelliJ###
*.iml
*.ipr
*.iws
.idea/
###Actionscript###
# Build and Release Folders
bin/
bin-debug/
bin-release/
# Project property files
.actionScriptProperties
.flexProperties
.settings/
.project
###OSX###
.DS_Store
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes

View File

@ -1,191 +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:
You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
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
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.

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