├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── RELEASING.md ├── animation ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── animation │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── hwangjr │ │ │ └── utils │ │ │ └── animation │ │ │ ├── AnimationHelper.java │ │ │ └── CustomAnim.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── hwangjr │ └── utils │ └── animation │ └── ExampleUnitTest.java ├── application ├── .gitignore ├── README.md ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── application │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── application │ │ ├── AppDataCleaner.java │ │ ├── AppHelper.java │ │ ├── CrashHelper.java │ │ ├── ManifestHelper.java │ │ ├── PackageHelper.java │ │ ├── PermissionHelper.java │ │ ├── Resource.java │ │ ├── ResourceHelper.java │ │ ├── ShortCutHelper.java │ │ ├── ViewHelper.java │ │ └── WindowHelper.java │ └── test │ └── java │ └── com │ └── hwangjr │ └── utils │ └── application │ └── ExampleUnitTest.java ├── basic ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── basic │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── basic │ │ ├── ClassHelper.java │ │ └── ObjectHelper.java │ └── test │ └── java │ └── com │ └── hwangjr │ └── utils │ └── basic │ └── ExampleUnitTest.java ├── build.gradle ├── checkstyle.xml ├── collection ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── collection │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── collection │ │ ├── ArrayHelper.java │ │ ├── CollectionHelper.java │ │ ├── CollectionPicker.java │ │ ├── ListHelper.java │ │ └── MapHelper.java │ └── test │ └── java │ └── com │ └── hwangjr │ └── utils │ └── collection │ └── ExampleUnitTest.java ├── debug ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── debug │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── debug │ │ ├── AppWatcher.java │ │ └── StrictModeHelper.java │ └── test │ └── java │ └── com │ └── hwangjr │ └── utils │ └── debug │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle ├── gradle-mvn-push.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── json ├── .gitignore ├── README.md ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── json │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── json │ │ ├── GSONWrapper.java │ │ ├── JSONGetter.java │ │ ├── JSONNode.java │ │ └── JSONResolver.java │ └── test │ └── java │ └── com │ └── hwangjr │ └── utils │ └── json │ └── ExampleUnitTest.java ├── screen ├── .gitignore ├── README.md ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── screen │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── screen │ │ ├── DensityConverter.java │ │ ├── ScreenHelper.java │ │ └── ScreenShoot.java │ └── test │ └── java │ └── com │ └── hwangjr │ └── utils │ └── screen │ └── ExampleUnitTest.java ├── settings.gradle ├── shell ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── shell │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── shell │ │ └── ShellHelper.java │ └── test │ └── java │ └── com │ └── hwangjr │ └── utils │ └── shell │ └── ExampleUnitTest.java ├── softinput ├── .gitignore ├── README.md ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── softinput │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── softinput │ │ └── SoftInput.java │ └── test │ └── java │ └── com │ └── hwangjr │ └── utils │ └── softinput │ └── ExampleUnitTest.java ├── templete ├── .gitignore ├── README.md ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hwangjr │ │ └── utils │ │ └── templete │ │ └── ApplicationTest.java │ ├── main │ └── AndroidManifest.xml │ └── test │ └── java │ └── com │ └── hwangjr │ └── utils │ └── templete │ └── ExampleUnitTest.java ├── timber ├── .gitignore ├── README.md ├── build.gradle ├── consumer-proguard-rules.pro ├── gradle.properties └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── timber │ │ └── log │ │ └── Timber.java │ └── test │ └── java │ └── timber │ └── log │ └── TimberTest.java └── xml ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── hwangjr │ └── utils │ └── xml │ └── ApplicationTest.java ├── main ├── AndroidManifest.xml └── java │ └── com │ └── hwangjr │ └── utils │ └── xml │ ├── XMLNode.java │ └── XMLResolver.java └── test └── java └── com └── hwangjr └── utils └── xml └── ExampleUnitTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | /*/build/ 19 | jniLibs 20 | local.properties 21 | reports 22 | 23 | # Local configuration file (sdk path, etc) 24 | local.properties 25 | 26 | # Proguard folder generated by Eclipse 27 | proguard/ 28 | 29 | # Log Files 30 | *.log 31 | 32 | # idea 33 | .idea/ 34 | 35 | .classpath 36 | .project 37 | .settings 38 | eclipsebin 39 | 40 | out 41 | lib 42 | 43 | *.iml 44 | classes 45 | 46 | obj 47 | 48 | .DS_Store 49 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Change Log 2 | ========== 3 | 4 | Version 1.0.3 *(2015-12-22)* 5 | --------------------------- 6 | * SoftInput to 1.0.1 { Add hide/show function } 7 | * Json to 1.0.0 8 | * XML to 1.0.0 9 | 10 | Version 1.0.2 *(2015-12-09)* 11 | --------------------------- 12 | * Timber to 4.1.0.0 (Modify package) 13 | 14 | Version 1.0.1 *(2015-12-03)* 15 | --------------------------- 16 | * Timber to 4.1.0 17 | * SoftInput to 1.0.0 18 | * A separate version of modules 19 | 20 | Version 1.0.0 *(2015-11-23)* 21 | ---------------------------- 22 | 23 | Initial, Add [JakeWharton/timber](https://github.com/JakeWharton/timber). -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Utils 2 | ------ 3 | 4 | This is a utils library with a small, extensible API which providers utility on top of Android's application develop. 5 | 6 | I copy this utils into all the little apps I make, I'm tired of doing it, I'm lazzy. Now it's a library. 7 | 8 | Now this utils have : 9 | * `timber` for log, you also won't miss [Pidcat](http://github.com/JakeWharton/pidcat/). 10 | 11 | Usage 12 | ----- 13 | 14 | **Gradle Build** 15 | 16 | Add libraries to your dependencies: 17 | ``` gradle 18 | dependencies { 19 | ... 20 | compile 'com.hwangjr.utils:timber:4.1.0.0' 21 | compile 'com.hwangjr.utils:softinput:1.0.1' 22 | compile 'com.hwangjr.utils:json:1.0.0' 23 | compile 'com.hwangjr.utils:xml:1.0.0' 24 | } 25 | ``` 26 | 27 | **Timber** 28 | 29 | Two easy steps: 30 | 31 | 1. Install any `Tree` instances you want in the `onCreate` of your application class. 32 | 2. Call `Timber`'s static methods everywhere throughout your app. 33 | 34 | **SoftInput** 35 | 36 | Just Call The Function. More In [SoftInput README](softinput/README.md) 37 | 38 | License 39 | ------- 40 | 41 | Copyright 2015 HwangJR 42 | 43 | Licensed under the Apache License, Version 2.0 (the "License"); 44 | you may not use this file except in compliance with the License. 45 | You may obtain a copy of the License at 46 | 47 | http://www.apache.org/licenses/LICENSE-2.0 48 | 49 | Unless required by applicable law or agreed to in writing, software 50 | distributed under the License is distributed on an "AS IS" BASIS, 51 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 52 | See the License for the specific language governing permissions and 53 | limitations under the License. 54 | 55 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | Releasing 2 | ======== 3 | 4 | 1. Change the version in `gradle.properties` to a non-SNAPSHOT version. 5 | 2. Update the `CHANGELOG.md` for the impending release. 6 | 3. Update the `README.md` with the new version. 7 | 4. `git commit -am "Prepare for release X.Y.Z."` (where X.Y.Z is the new version) 8 | 5. `./gradlew clean uploadArchives` 9 | 6. `git tag -a X.Y.Z -m "Version X.Y.Z"` (where X.Y.Z is the new version) 10 | 7. Update the `gradle.properties` to the next SNAPSHOT version. 11 | 8. `git commit -am "Prepare next development version."` 12 | 9. `git push && git push --tags` 13 | 10. Visit [Sonatype Nexus](https://oss.sonatype.org/) and promote the artifact. 14 | 15 | Add New Module 16 | ======== 17 | 18 | 1. New Module For Project 19 | 2. Copy `timber/gradle.properties` and modify 20 | 3. Modify `module/build.gradle`, consider the `timber/build.gradle` or other `build.gradle` 21 | 4. Option, del res, modify `manifest` -------------------------------------------------------------------------------- /animation/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /animation/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 9 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | testCompile 'junit:junit:4.12' 24 | compile 'com.android.support:appcompat-v7:23.1.1' 25 | } 26 | -------------------------------------------------------------------------------- /animation/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /animation/src/androidTest/java/com/hwangjr/utils/animation/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.animation; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /animation/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /animation/src/main/java/com/hwangjr/utils/animation/CustomAnim.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.animation; 2 | 3 | import android.view.animation.AlphaAnimation; 4 | import android.view.animation.Animation; 5 | import android.view.animation.RotateAnimation; 6 | import android.view.animation.ScaleAnimation; 7 | 8 | public class CustomAnim { 9 | 10 | /** 11 | * Don't let anyone instantiate this class. 12 | */ 13 | private CustomAnim() { 14 | throw new Error("Do not need instantiate!"); 15 | } 16 | 17 | /** 18 | * get a rotation animation 19 | * 20 | * @param fromDegrees Rotation offset to apply at the start of the 21 | * animation. 22 | * @param toDegrees Rotation offset to apply at the end of the animation. 23 | * @param pivotXType Specifies how pivotXValue should be interpreted. One of 24 | * Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or 25 | * Animation.RELATIVE_TO_PARENT. 26 | * @param pivotXValue The X coordinate of the point about which the object 27 | * is being rotated, specified as an absolute number where 0 is the 28 | * left edge. This value can either be an absolute number if 29 | * pivotXType is ABSOLUTE, or a percentage (where 1.0 is 100%) 30 | * otherwise. 31 | * @param pivotYType Specifies how pivotYValue should be interpreted. One of 32 | * Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or 33 | * Animation.RELATIVE_TO_PARENT. 34 | * @param pivotYValue The Y coordinate of the point about which the object 35 | * is being rotated, specified as an absolute number where 0 is the 36 | * top edge. This value can either be an absolute number if 37 | * pivotYType is ABSOLUTE, or a percentage (where 1.0 is 100%) 38 | * otherwise. 39 | * @param durationMillis Duration in milliseconds 40 | * @param listener the animation listener to be notified 41 | * @return rotation animation 42 | */ 43 | public static RotateAnimation getRotateAnimation(float fromDegrees, float toDegrees, int pivotXType, 44 | float pivotXValue, int pivotYType, float pivotYValue, 45 | long durationMillis, Animation.AnimationListener listener) { 46 | RotateAnimation rotateAnimation = new RotateAnimation(fromDegrees, 47 | toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue); 48 | rotateAnimation.setDuration(durationMillis); 49 | if (listener != null) { 50 | rotateAnimation.setAnimationListener(listener); 51 | } 52 | return rotateAnimation; 53 | } 54 | 55 | /** 56 | * get an animation rotate by view center point. 57 | * 58 | * @param durationMillis Duration in milliseconds 59 | * @param listener the animation listener to be notified 60 | * @return animation rotate by view center point 61 | */ 62 | public static RotateAnimation getRotateAnimationByCenter(long durationMillis, Animation.AnimationListener listener) { 63 | return getRotateAnimation(0f, 359f, Animation.RELATIVE_TO_SELF, 0.5f, 64 | Animation.RELATIVE_TO_SELF, 0.5f, durationMillis, 65 | listener); 66 | } 67 | 68 | /** 69 | * get an animation rotate by view center point. 70 | * 71 | * @param durationMillis Duration in milliseconds 72 | * @return animation rotate by view center point 73 | */ 74 | public static RotateAnimation getRotateAnimationByCenter(long durationMillis) { 75 | return getRotateAnimationByCenter(durationMillis, null); 76 | } 77 | 78 | /** 79 | * get an animation rotate by view center point. 80 | * 81 | * @param listener the animation listener to be notified 82 | * @return animation rotate by view center point 83 | */ 84 | public static RotateAnimation getRotateAnimationByCenter(Animation.AnimationListener listener) { 85 | return getRotateAnimationByCenter(AnimationHelper.DEFAULT_ANIMATION_DURATION, listener); 86 | } 87 | 88 | /** 89 | * get an animation rotate by view center point. 90 | * animation duration is {@link AnimationHelper#DEFAULT_ANIMATION_DURATION} 91 | * 92 | * @return animation rotate by view center point 93 | */ 94 | public static RotateAnimation getRotateAnimationByCenter() { 95 | return getRotateAnimationByCenter(AnimationHelper.DEFAULT_ANIMATION_DURATION, null); 96 | } 97 | 98 | /** 99 | * get an alpha animation. 100 | * 101 | * @param fromAlpha Starting alpha value for the animation, where 1.0 means 102 | * fully opaque and 0.0 means fully transparent. 103 | * @param toAlpha Ending alpha value for the animation. 104 | * @param durationMillis Duration in milliseconds 105 | * @param listener the animation listener to be notified 106 | * @return An animation that controls the alpha level of an object. 107 | */ 108 | public static AlphaAnimation getAlphaAnimation(float fromAlpha, float toAlpha, long durationMillis, 109 | Animation.AnimationListener listener) { 110 | AlphaAnimation alphaAnimation = new AlphaAnimation(fromAlpha, toAlpha); 111 | alphaAnimation.setDuration(durationMillis); 112 | if (listener != null) { 113 | alphaAnimation.setAnimationListener(listener); 114 | } 115 | return alphaAnimation; 116 | } 117 | 118 | /** 119 | * get an alpha animation. 120 | * 121 | * @param fromAlpha Starting alpha value for the animation, where 1.0 means 122 | * fully opaque and 0.0 means fully transparent. 123 | * @param toAlpha Ending alpha value for the animation. 124 | * @param durationMillis Duration in milliseconds 125 | * @return An animation that controls the alpha level of an object. 126 | */ 127 | public static AlphaAnimation getAlphaAnimation(float fromAlpha, float toAlpha, long durationMillis) { 128 | return getAlphaAnimation(fromAlpha, toAlpha, durationMillis, null); 129 | } 130 | 131 | /** 132 | * get an alpha animation. duration is {@link AnimationHelper#DEFAULT_ANIMATION_DURATION}. 133 | * 134 | * @param fromAlpha Starting alpha value for the animation, where 1.0 means 135 | * fully opaque and 0.0 means fully transparent. 136 | * @param toAlpha Ending alpha value for the animation. 137 | * @param listener the animation listener to be notified 138 | * @return An animation that controls the alpha level of an object. 139 | */ 140 | public static AlphaAnimation getAlphaAnimation(float fromAlpha, float toAlpha, Animation.AnimationListener listener) { 141 | return getAlphaAnimation(fromAlpha, toAlpha, AnimationHelper.DEFAULT_ANIMATION_DURATION, listener); 142 | } 143 | 144 | /** 145 | * get an alpha animation. duration is {@link AnimationHelper#DEFAULT_ANIMATION_DURATION}. 146 | * 147 | * @param fromAlpha Starting alpha value for the animation, where 1.0 means 148 | * fully opaque and 0.0 means fully transparent. 149 | * @param toAlpha Ending alpha value for the animation. 150 | * @return An animation that controls the alpha level of an object. 151 | */ 152 | public static AlphaAnimation getAlphaAnimation(float fromAlpha, float toAlpha) { 153 | return getAlphaAnimation(fromAlpha, toAlpha, AnimationHelper.DEFAULT_ANIMATION_DURATION, null); 154 | } 155 | 156 | /** 157 | * get an animation from visible to invisible by changing alpha. 158 | * 159 | * @param durationMillis Duration in milliseconds 160 | * @param listener the animation listener to be notified 161 | * @return an animation from visible to invisible by changing alpha 162 | */ 163 | public static AlphaAnimation getVisibleAlphaAnimation(long durationMillis, Animation.AnimationListener listener) { 164 | return getAlphaAnimation(1.0f, 0.0f, durationMillis, listener); 165 | } 166 | 167 | /** 168 | * get an animation from visible to invisible by changing alpha. 169 | * 170 | * @param durationMillis Duration in milliseconds 171 | * @return an animation from visible to invisible by changing alpha 172 | */ 173 | public static AlphaAnimation getVisibleAlphaAnimation(long durationMillis) { 174 | return getVisibleAlphaAnimation(durationMillis, null); 175 | } 176 | 177 | /** 178 | * get an animation from visible to invisible by changing alpha. 179 | * default duration is {@link AnimationHelper#DEFAULT_ANIMATION_DURATION} 180 | * 181 | * @param listener the animation listener to be notified 182 | * @return an animation from visible to invisible by changing alpha 183 | */ 184 | public static AlphaAnimation getVisibleAlphaAnimation(Animation.AnimationListener listener) { 185 | return getVisibleAlphaAnimation(AnimationHelper.DEFAULT_ANIMATION_DURATION, listener); 186 | } 187 | 188 | /** 189 | * get an animation from visible to invisible by changing alpha. 190 | * default duration is {@link AnimationHelper#DEFAULT_ANIMATION_DURATION} 191 | * 192 | * @return an animation from visible to invisible by changing alpha 193 | */ 194 | public static AlphaAnimation getVisibleAlphaAnimation() { 195 | return getVisibleAlphaAnimation(AnimationHelper.DEFAULT_ANIMATION_DURATION, null); 196 | } 197 | 198 | /** 199 | * get an animation from invisible to visible by changing alpha. 200 | * 201 | * @param durationMillis Duration in milliseconds 202 | * @param listener the animation listener to be notified 203 | * @return an animation from invisible to visible by changing alpha 204 | */ 205 | public static AlphaAnimation getInvisibleAlphaAnimation(long durationMillis, Animation.AnimationListener listener) { 206 | return getAlphaAnimation(0.0f, 1.0f, durationMillis, listener); 207 | } 208 | 209 | /** 210 | * get an animation from invisible to visible by changing alpha. 211 | * 212 | * @param durationMillis Duration in milliseconds 213 | * @return an animation from invisible to visible by changing alpha 214 | */ 215 | public static AlphaAnimation getInvisibleAlphaAnimation(long durationMillis) { 216 | return getAlphaAnimation(0.0f, 1.0f, durationMillis, null); 217 | } 218 | 219 | /** 220 | * get an animation from invisible to visible by changing alpha. 221 | * default duration is {@link AnimationHelper#DEFAULT_ANIMATION_DURATION} 222 | * 223 | * @param listener the animation listener to be notified 224 | * @return an animation from invisible to visible by changing alpha 225 | */ 226 | public static AlphaAnimation getInvisibleAlphaAnimation(Animation.AnimationListener listener) { 227 | return getAlphaAnimation(0.0f, 1.0f, AnimationHelper.DEFAULT_ANIMATION_DURATION, listener); 228 | } 229 | 230 | /** 231 | * get an animation from invisible to visible by changing alpha. 232 | * default duration is {@link AnimationHelper#DEFAULT_ANIMATION_DURATION} 233 | * 234 | * @return an animation from invisible to visible by changing alpha 235 | */ 236 | public static AlphaAnimation getInvisibleAlphaAnimation() { 237 | return getAlphaAnimation(0.0f, 1.0f, AnimationHelper.DEFAULT_ANIMATION_DURATION, null); 238 | } 239 | 240 | /** 241 | * get a lessen scale animation 242 | * 243 | * @param durationMillis Duration in milliseconds 244 | * @param listener the animation listener to be notified 245 | * @return An animation that controls the lessen scale of an object 246 | */ 247 | public static ScaleAnimation getLessenScaleAnimation(long durationMillis, Animation.AnimationListener listener) { 248 | ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 0.0f, 1.0f, 249 | 0.0f, ScaleAnimation.RELATIVE_TO_SELF, 250 | ScaleAnimation.RELATIVE_TO_SELF); 251 | scaleAnimation.setDuration(durationMillis); 252 | scaleAnimation.setAnimationListener(listener); 253 | return scaleAnimation; 254 | } 255 | 256 | /** 257 | * get a lessen scale animation 258 | * 259 | * @param durationMillis Duration in milliseconds 260 | * @return An animation that controls the lessen scale of an object 261 | */ 262 | public static ScaleAnimation getLessenScaleAnimation(long durationMillis) { 263 | return getLessenScaleAnimation(durationMillis, null); 264 | 265 | } 266 | 267 | /** 268 | * get a lessen scale animation 269 | * 270 | * @param listener the animation listener to be notified 271 | * @return An animation that controls the lessen scale of an object 272 | */ 273 | public static ScaleAnimation getLessenScaleAnimation(Animation.AnimationListener listener) { 274 | return getLessenScaleAnimation(AnimationHelper.DEFAULT_ANIMATION_DURATION, listener); 275 | 276 | } 277 | 278 | /** 279 | * get a amplification scale animation 280 | * 281 | * @param durationMillis Duration in milliseconds 282 | * @param listener the animation listener to be notified 283 | * @return An animation that controls the amplification scale of an object 284 | */ 285 | public static ScaleAnimation getAmplificationAnimation(long durationMillis, Animation.AnimationListener listener) { 286 | ScaleAnimation scaleAnimation = new ScaleAnimation(0.0f, 1.0f, 0.0f, 287 | 1.0f, ScaleAnimation.RELATIVE_TO_SELF, 288 | ScaleAnimation.RELATIVE_TO_SELF); 289 | scaleAnimation.setDuration(durationMillis); 290 | scaleAnimation.setAnimationListener(listener); 291 | return scaleAnimation; 292 | } 293 | 294 | /** 295 | * get a amplification scale animation 296 | * 297 | * @param durationMillis Duration in milliseconds 298 | * @return An animation that controls the amplification scale of an object 299 | */ 300 | public static ScaleAnimation getAmplificationAnimation(long durationMillis) { 301 | return getAmplificationAnimation(durationMillis, null); 302 | } 303 | 304 | /** 305 | * get a amplification scale animation 306 | * 307 | * @param listener the animation listener to be notified 308 | * @return An animation that controls the amplification scale of an object 309 | */ 310 | public static ScaleAnimation getAmplificationAnimation(Animation.AnimationListener listener) { 311 | return getAmplificationAnimation(AnimationHelper.DEFAULT_ANIMATION_DURATION, listener); 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /animation/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Animation 3 | 4 | -------------------------------------------------------------------------------- /animation/src/test/java/com/hwangjr/utils/animation/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.animation; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /application/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /application/README.md: -------------------------------------------------------------------------------- 1 | Templete 2 | ------ 3 | This is a library templete. 4 | 5 | Usage 6 | ----- 7 | Copy the files. 8 | 9 | More 10 | ------ 11 | None -------------------------------------------------------------------------------- /application/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'checkstyle' 3 | 4 | task checkstyle(type: Checkstyle) { 5 | configFile rootProject.file('checkstyle.xml') 6 | source 'src/main/java' 7 | ignoreFailures false 8 | showViolations true 9 | include '**/*.java' 10 | 11 | classpath = files() 12 | } 13 | 14 | afterEvaluate { 15 | if (project.tasks.findByName('check')) { 16 | check.dependsOn('checkstyle') 17 | } 18 | } 19 | 20 | android { 21 | compileSdkVersion rootProject.ext.compileSdkVersion 22 | buildToolsVersion rootProject.ext.buildToolsVersion 23 | 24 | defaultConfig { 25 | minSdkVersion rootProject.ext.minSdkVersion 26 | targetSdkVersion rootProject.ext.targetSdkVersion 27 | consumerProguardFiles 'proguard-rules.pro' 28 | } 29 | } 30 | 31 | dependencies { 32 | compile project(':basic') 33 | compile project(':collection') 34 | compile project(':shell') 35 | } 36 | 37 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') -------------------------------------------------------------------------------- /application/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=Application 2 | POM_NAME=application 3 | POM_PACKAGING=aar 4 | 5 | #VERSION_NAME=1.0.0-SNAPSHOT -------------------------------------------------------------------------------- /application/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /application/src/androidTest/java/com/hwangjr/utils/application/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.application; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /application/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /application/src/main/java/com/hwangjr/utils/application/AppDataCleaner.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.application; 2 | 3 | import android.content.Context; 4 | import android.os.Environment; 5 | 6 | import java.io.File; 7 | import java.math.BigDecimal; 8 | 9 | /** 10 | * Clean app data 11 | */ 12 | public class AppDataCleaner { 13 | /** 14 | * clean up app internal cache (/data/data/package.name/cache) 15 | * 16 | * @param context 17 | */ 18 | public static void cleanInternalCache(Context context) { 19 | deleteFilesByDirectory(context.getCacheDir()); 20 | } 21 | 22 | /** 23 | * clean up app internal database (/data/data/package.name/databases) 24 | * 25 | * @param context 26 | */ 27 | public static void cleanDatabases(Context context) { 28 | deleteFilesByDirectory(new File(context.getFilesDir().getPath() 29 | + context.getPackageName() + "/databases")); 30 | } 31 | 32 | /** 33 | * clean up app shared preference (/data/data/package.name/shared_prefs) 34 | * 35 | * @param context 上下文 36 | */ 37 | public static void cleanSharedPreference(Context context) { 38 | deleteFilesByDirectory(new File(context.getFilesDir().getPath() 39 | + context.getPackageName() + "/shared_prefs")); 40 | } 41 | 42 | /** 43 | * clean up app database by name (/data/data/package.name/databases/dbname) 44 | * 45 | * @param context application context 46 | * @param dbName name of database 47 | */ 48 | public static void cleanDatabaseByName(Context context, String dbName) { 49 | context.deleteDatabase(dbName); 50 | } 51 | 52 | /** 53 | * clean up app files (/data/data/package.name/files) 54 | * 55 | * @param context 56 | */ 57 | public static void cleanFiles(Context context) { 58 | deleteFilesByDirectory(context.getFilesDir()); 59 | } 60 | 61 | /** 62 | * clean up app external cache (/mnt/sdcard/android/data/package.name/cache) 63 | * 64 | * @param context 65 | */ 66 | public static void cleanExternalCache(Context context) { 67 | if (Environment.getExternalStorageState().equals( 68 | Environment.MEDIA_MOUNTED)) { 69 | deleteFilesByDirectory(context.getExternalCacheDir()); 70 | } 71 | } 72 | 73 | /** 74 | * clean up the file/directory 75 | * 76 | * @param filePath file 77 | */ 78 | public static void cleanCache(String filePath) { 79 | File file = new File(filePath); 80 | if (file.isDirectory()) { 81 | deleteFilesByDirectory(new File(filePath)); 82 | } else { 83 | file.delete(); 84 | } 85 | } 86 | 87 | /** 88 | * 清除本应用所有的数据 89 | * clean up all application data: internal cache, external cache, databases, shared preference, etc. 90 | * 91 | * @param context application context 92 | * @param filePath file paths to be deleted 93 | */ 94 | public static void cleanApplicationData(Context context, String... filePath) { 95 | cleanInternalCache(context); 96 | cleanExternalCache(context); 97 | cleanDatabases(context); 98 | cleanSharedPreference(context); 99 | cleanFiles(context); 100 | for (String fp : filePath) { 101 | cleanCache(fp); 102 | } 103 | } 104 | 105 | /** 106 | * delete directory, if directory is a file, then will do nothing. 107 | * 108 | * @param directory to be deleted 109 | */ 110 | private static void deleteFilesByDirectory(File directory) { 111 | if (directory != null && directory.exists() && directory.isDirectory()) { 112 | for (File item : directory.listFiles()) { 113 | item.delete(); 114 | } 115 | } 116 | } 117 | 118 | 119 | /** 120 | * get the size for the file, the size does not format. 121 | * 122 | * @param file 123 | * @return 124 | * @throws Exception 125 | */ 126 | public static long getFileSize(File file) throws Exception { 127 | long size = 0; 128 | try { 129 | if (file.isDirectory()) { 130 | File[] fileList = file.listFiles(); 131 | for (int i = 0; i < fileList.length; i++) { 132 | size = size + getFileSize(fileList[i]); 133 | } 134 | } else { 135 | size = file.length(); 136 | } 137 | } catch (Exception e) { 138 | e.printStackTrace(); 139 | } 140 | return size; 141 | } 142 | 143 | /** 144 | * get the format file size 145 | * @param file 146 | * @return 147 | * @throws Exception 148 | */ 149 | public static String getFormatSize(File file) throws Exception { 150 | return getFormatSize(getFileSize(file)); 151 | } 152 | 153 | /** 154 | * format the size(byte, kb, mb, gb, tb) 155 | * 156 | * @param size file size 157 | * @return 158 | */ 159 | public static String getFormatSize(double size) { 160 | double kiloByte = size / 1024; 161 | if (kiloByte < 1) { 162 | return size + "Byte"; 163 | } 164 | 165 | double megaByte = kiloByte / 1024; 166 | if (megaByte < 1) { 167 | BigDecimal result1 = new BigDecimal(Double.toString(kiloByte)); 168 | return result1.setScale(2, BigDecimal.ROUND_HALF_UP) 169 | .toPlainString() + "KB"; 170 | } 171 | 172 | double gigaByte = megaByte / 1024; 173 | if (gigaByte < 1) { 174 | BigDecimal result2 = new BigDecimal(Double.toString(megaByte)); 175 | return result2.setScale(2, BigDecimal.ROUND_HALF_UP) 176 | .toPlainString() + "MB"; 177 | } 178 | 179 | double teraBytes = gigaByte / 1024; 180 | if (teraBytes < 1) { 181 | BigDecimal result3 = new BigDecimal(Double.toString(gigaByte)); 182 | return result3.setScale(2, BigDecimal.ROUND_HALF_UP) 183 | .toPlainString() + "GB"; 184 | } 185 | BigDecimal result4 = new BigDecimal(teraBytes); 186 | return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() 187 | + "TB"; 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /application/src/main/java/com/hwangjr/utils/application/CrashHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.application; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.content.pm.PackageManager.NameNotFoundException; 7 | import android.os.Build; 8 | import android.os.Environment; 9 | import android.os.Looper; 10 | import android.text.TextUtils; 11 | import android.widget.Toast; 12 | 13 | import java.io.File; 14 | import java.io.FileOutputStream; 15 | import java.io.PrintWriter; 16 | import java.io.StringWriter; 17 | import java.io.Writer; 18 | import java.lang.Thread.UncaughtExceptionHandler; 19 | import java.lang.reflect.Field; 20 | import java.text.SimpleDateFormat; 21 | import java.util.Date; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | public class CrashHelper implements UncaughtExceptionHandler { 26 | 27 | private static CrashHelper INSTANCE = new CrashHelper(); 28 | 29 | private String showMessage = "Opps, App has crashed, we will fixed it soon!"; 30 | private UncaughtExceptionHandler mDefaultHandler; 31 | private Context mContext; 32 | 33 | //As part of file name 34 | private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); 35 | private String crashFilePath = "/crash/"; 36 | 37 | private CrashHelper() { 38 | } 39 | 40 | /** 41 | * Singleton 42 | */ 43 | public static CrashHelper getInstance() { 44 | return INSTANCE; 45 | } 46 | 47 | /** 48 | * Initialize 49 | * 50 | * @param context 51 | * @param crashFilePath 52 | */ 53 | public void init(Context context, String crashFilePath, String showMessage) { 54 | mContext = context; 55 | mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); 56 | Thread.setDefaultUncaughtExceptionHandler(this); 57 | this.crashFilePath = crashFilePath; 58 | if (!TextUtils.isEmpty(showMessage)) { 59 | this.showMessage = showMessage; 60 | } 61 | } 62 | 63 | /** 64 | * Initialize 65 | * 66 | * @param context 67 | */ 68 | public void init(Context context) { 69 | init(context, "/crash/" + context.getPackageName()); 70 | } 71 | 72 | /** 73 | * Initialize 74 | * 75 | * @param context 76 | */ 77 | public void init(Context context, String crashFilePath) { 78 | init(context, crashFilePath, ""); 79 | } 80 | 81 | @Override 82 | public void uncaughtException(Thread thread, Throwable ex) { 83 | if (!handleException(ex) && mDefaultHandler != null) { 84 | mDefaultHandler.uncaughtException(thread, ex); 85 | } else { 86 | try { 87 | Thread.sleep(100); 88 | } catch (InterruptedException e) { 89 | e.printStackTrace(); 90 | } 91 | System.exit(0); 92 | android.os.Process.killProcess(android.os.Process.myPid()); 93 | } 94 | } 95 | 96 | 97 | private boolean handleException(Throwable ex) { 98 | if (ex == null) { 99 | return false; 100 | } 101 | new Thread() { 102 | @Override 103 | public void run() { 104 | Looper.prepare(); 105 | Toast.makeText(mContext, showMessage, Toast.LENGTH_SHORT).show(); 106 | Looper.loop(); 107 | } 108 | }.start(); 109 | saveCrashInfo2File(ex, getDeviceInfo(mContext)); 110 | return true; 111 | } 112 | 113 | /** 114 | * Collect Device info 115 | */ 116 | public Map getDeviceInfo(Context context) { 117 | Map infos = new HashMap<>(); 118 | try { 119 | PackageManager pm = context.getPackageManager(); 120 | PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES); 121 | if (packageInfo != null) { 122 | String versionName = packageInfo.versionName == null ? "null" : packageInfo.versionName; 123 | String versionCode = packageInfo.versionCode + ""; 124 | infos.put("versionName", versionName); 125 | infos.put("versionCode", versionCode); 126 | } 127 | } catch (NameNotFoundException e) { 128 | e.printStackTrace(); 129 | } 130 | Field[] fields = Build.class.getDeclaredFields(); 131 | for (Field field : fields) { 132 | try { 133 | field.setAccessible(true); 134 | infos.put(field.getName(), field.get(null).toString()); 135 | } catch (Exception e) { 136 | e.printStackTrace(); 137 | } 138 | } 139 | return infos; 140 | } 141 | 142 | /** 143 | * Save Info to files 144 | */ 145 | private String saveCrashInfo2File(Throwable throwable, Map info) { 146 | StringBuffer buffer = new StringBuffer(); 147 | for (Map.Entry entry : info.entrySet()) { 148 | String key = entry.getKey(); 149 | String value = entry.getValue(); 150 | buffer.append(key + "=" + value + "\n"); 151 | } 152 | 153 | Writer writer = new StringWriter(); 154 | PrintWriter printWriter = new PrintWriter(writer); 155 | throwable.printStackTrace(printWriter); 156 | Throwable cause = throwable.getCause(); 157 | while (cause != null) { 158 | cause.printStackTrace(printWriter); 159 | cause = cause.getCause(); 160 | } 161 | printWriter.close(); 162 | String result = writer.toString(); 163 | buffer.append(result); 164 | try { 165 | long timestamp = System.currentTimeMillis(); 166 | String time = formatter.format(new Date()); 167 | String fileName = "crash-" + time + "-" + timestamp + ".log"; 168 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 169 | String path = 170 | Environment.getExternalStorageDirectory().getAbsolutePath() + 171 | (!TextUtils.isEmpty(crashFilePath) ? crashFilePath : "/crash/"); 172 | File dir = new File(path); 173 | if (!dir.exists()) { 174 | dir.mkdirs(); 175 | } 176 | FileOutputStream fos = new FileOutputStream(path + fileName); 177 | fos.write(buffer.toString().getBytes()); 178 | fos.close(); 179 | } 180 | return fileName; 181 | } catch (Exception e) { 182 | e.printStackTrace(); 183 | } 184 | return null; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /application/src/main/java/com/hwangjr/utils/application/ManifestHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.application; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageManager; 5 | import android.os.Bundle; 6 | 7 | public class ManifestHelper { 8 | 9 | /** 10 | * get package name 11 | */ 12 | public static String getPackageName(Context context) { 13 | try { 14 | return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).packageName; 15 | } catch (PackageManager.NameNotFoundException e) { 16 | e.printStackTrace(); 17 | } 18 | return null; 19 | } 20 | 21 | /** 22 | * get meta data from manifest 23 | * 24 | * @param context 25 | * @param key key 26 | * @return value 27 | */ 28 | public static String getMetadata(Context context, String key) { 29 | try { 30 | Bundle metaData = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA).metaData; 31 | return metaData.get(key).toString(); 32 | } catch (PackageManager.NameNotFoundException e) { 33 | e.printStackTrace(); 34 | } 35 | return null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /application/src/main/java/com/hwangjr/utils/application/PermissionHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.application; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.os.Build; 7 | import android.os.Process; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.List; 12 | 13 | /** 14 | * Check permission and get application granted permissions. 15 | */ 16 | public class PermissionHelper { 17 | /** 18 | * whether lack of permissions, {@link #lacksPermission(Context, String)} 19 | * 20 | * @param context 21 | * @param permissions 22 | * @return 23 | */ 24 | public static boolean lacksPermissions(Context context, String... permissions) { 25 | for (String permission : permissions) { 26 | if (lacksPermission(context, permission)) { 27 | return true; 28 | } 29 | } 30 | return false; 31 | } 32 | 33 | /** 34 | * whether lack of permission. if on per-Marshmallow devices, it will call {@link PackageManager#checkPermission(String, String)}, 35 | * otherwise, it will call {@link #checkSelfPermission(Context, String)}. 36 | * 37 | * @param context 38 | * @param permission 39 | * @return 40 | */ 41 | public static boolean lacksPermission(Context context, String permission) { 42 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 43 | return checkSelfPermission(context, permission) == PackageManager.PERMISSION_DENIED; 44 | } else { 45 | return context.getPackageManager().checkPermission(permission, context.getPackageName()) == PackageManager.PERMISSION_DENIED; 46 | } 47 | } 48 | 49 | /** 50 | * Determine whether you have been granted a particular permission. 51 | * 52 | * @param permission The name of the permission being checked. 53 | * @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if you have the 54 | * permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} if not. 55 | * @see android.content.pm.PackageManager#checkPermission(String, String) 56 | */ 57 | public static int checkSelfPermission(Context context, String permission) { 58 | if (permission == null) { 59 | throw new IllegalArgumentException("permission is null"); 60 | } 61 | return context.checkPermission(permission, Process.myPid(), Process.myUid()); 62 | } 63 | 64 | /** 65 | * whether app has granted this permissions 66 | * 67 | * @param context 68 | * @param permissions Manifest.permission 69 | * @return true if app has, also false 70 | */ 71 | public static boolean isPermissionsGranted(Context context, String... permissions) { 72 | for (String permission : permissions) { 73 | if (!isPermissionGranted(context, permission)) { 74 | return false; 75 | } 76 | } 77 | return true; 78 | } 79 | 80 | /** 81 | * whether app has granted this permission 82 | * 83 | * @param context 84 | * @param permission Manifest.permission 85 | * @return true if app has, also false 86 | */ 87 | public static boolean isPermissionGranted(Context context, String permission) { 88 | return PackageManager.PERMISSION_GRANTED == context.getPackageManager().checkPermission(permission, context.getPackageName()); 89 | } 90 | 91 | /** 92 | * get granted permission list 93 | */ 94 | public static List getPermissions(Context context) { 95 | List permissions = new ArrayList<>(); 96 | try { 97 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS); 98 | permissions.addAll(Arrays.asList(packageInfo.requestedPermissions)); 99 | } catch (PackageManager.NameNotFoundException e) { 100 | e.printStackTrace(); 101 | } 102 | return permissions; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /application/src/main/java/com/hwangjr/utils/application/Resource.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.application; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageManager; 5 | import android.content.res.Resources; 6 | import android.graphics.drawable.Drawable; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.UnsupportedEncodingException; 11 | 12 | /** 13 | * Created by hwangjr on 12/24/15. 14 | */ 15 | public class Resource { 16 | } 17 | -------------------------------------------------------------------------------- /application/src/main/java/com/hwangjr/utils/application/ResourceHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.application; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.text.TextUtils; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.InputStreamReader; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public class ResourceHelper { 15 | 16 | public static final String LAYTOUT = "layout"; 17 | public static final String DRAWABLE = "drawable"; 18 | public static final String MIPMAP = "mipmap"; 19 | public static final String MENU = "menu"; 20 | public static final String RAW = "raw"; 21 | public static final String ANIM = "anim"; 22 | public static final String STRING = "string"; 23 | public static final String STYLE = "style"; 24 | public static final String STYLEABLE = "styleable"; 25 | public static final String INTEGER = "integer"; 26 | public static final String ID = "id"; 27 | public static final String DIMEN = "dimen"; 28 | public static final String COLOR = "color"; 29 | public static final String BOOL = "bool"; 30 | public static final String ATTR = "attr"; 31 | 32 | private ResourceHelper() { 33 | throw new AssertionError(); 34 | } 35 | 36 | /** 37 | * get resource id 38 | * 39 | * @param context 40 | * @param name resource name 41 | * @param type resource type, {@link #LAYTOUT} etc.. 42 | * @return resource id, if not found, return 0 43 | */ 44 | public static int getResourceId(Context context, String name, String type) { 45 | try { 46 | return context.getResources().getIdentifier(name, type, context.getPackageName()); 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | } 50 | return 0; 51 | } 52 | 53 | /** 54 | * get string by resource id 55 | * 56 | * @param context 57 | * @param stringId resource id 58 | * @return string of the resource 59 | */ 60 | public static String getString(Context context, int stringId) { 61 | return context.getResources().getString(stringId); 62 | } 63 | 64 | /** 65 | * get color 66 | * 67 | * @param context 68 | * @param colorId color id 69 | * @return color 70 | */ 71 | public static int getColor(Context context, int colorId) { 72 | return context.getResources().getColor(colorId); 73 | } 74 | 75 | /** 76 | * get drawable 77 | * 78 | * @param context 79 | * @param drawableId Drawable id 80 | * @return Drawable 81 | */ 82 | public static Drawable getDrawable(Context context, int drawableId) { 83 | return context.getResources().getDrawable(drawableId); 84 | } 85 | 86 | /** 87 | * get an asset using ACCESS_STREAMING mode. This provides access to files that have been bundled with an 88 | * application as assets -- that is, files placed in to the "assets" directory. 89 | * 90 | * @param context 91 | * @param fileName The name of the asset to open. This name can be hierarchical. 92 | * @return 93 | */ 94 | public static String getStringFromAssets(Context context, String fileName) { 95 | if (context == null || TextUtils.isEmpty(fileName)) { 96 | return null; 97 | } 98 | 99 | StringBuilder s = new StringBuilder(""); 100 | try { 101 | InputStreamReader in = new InputStreamReader(context.getResources().getAssets().open(fileName)); 102 | BufferedReader br = new BufferedReader(in); 103 | String line; 104 | while ((line = br.readLine()) != null) { 105 | s.append(line); 106 | } 107 | return s.toString(); 108 | } catch (IOException e) { 109 | e.printStackTrace(); 110 | return null; 111 | } 112 | } 113 | 114 | /** 115 | * get content from a raw resource. This can only be used with resources whose value is the name of an asset files 116 | * -- that is, it can be used to open drawable, sound, and raw resources; it will fail on string and color 117 | * resources. 118 | * 119 | * @param context 120 | * @param resId The resource identifier to open, as generated by the appt tool. 121 | * @return 122 | */ 123 | public static String getStringFromRaw(Context context, int resId) { 124 | if (context == null) { 125 | return null; 126 | } 127 | 128 | StringBuilder s = new StringBuilder(); 129 | try { 130 | InputStreamReader in = new InputStreamReader(context.getResources().openRawResource(resId)); 131 | BufferedReader br = new BufferedReader(in); 132 | String line; 133 | while ((line = br.readLine()) != null) { 134 | s.append(line); 135 | } 136 | return s.toString(); 137 | } catch (IOException e) { 138 | e.printStackTrace(); 139 | return null; 140 | } 141 | } 142 | 143 | /** 144 | * same to {@link #getStringFromAssets(Context, String)}, but return type is List 145 | * 146 | * @param context 147 | * @param fileName 148 | * @return 149 | */ 150 | public static List getStringListFromAssets(Context context, String fileName) { 151 | if (context == null || TextUtils.isEmpty(fileName)) { 152 | return null; 153 | } 154 | 155 | List fileContent = new ArrayList<>(); 156 | try { 157 | InputStreamReader in = new InputStreamReader(context.getResources().getAssets().open(fileName)); 158 | BufferedReader br = new BufferedReader(in); 159 | String line; 160 | while ((line = br.readLine()) != null) { 161 | fileContent.add(line); 162 | } 163 | br.close(); 164 | return fileContent; 165 | } catch (IOException e) { 166 | e.printStackTrace(); 167 | return null; 168 | } 169 | } 170 | 171 | /** 172 | * same to {@link #getStringFromRaw(Context, int)}, but return type is List 173 | * 174 | * @param context 175 | * @param resId 176 | * @return 177 | */ 178 | public static List getStringListFromRaw(Context context, int resId) { 179 | if (context == null) { 180 | return null; 181 | } 182 | 183 | List fileContent = new ArrayList<>(); 184 | try { 185 | InputStreamReader in = new InputStreamReader(context.getResources().openRawResource(resId)); 186 | BufferedReader reader = new BufferedReader(in); 187 | String line = null; 188 | while ((line = reader.readLine()) != null) { 189 | fileContent.add(line); 190 | } 191 | reader.close(); 192 | return fileContent; 193 | } catch (IOException e) { 194 | e.printStackTrace(); 195 | return null; 196 | } 197 | } 198 | 199 | /** 200 | * get bytes of the file from assert folder 201 | * 202 | * @param context 203 | * @param fileName file name 204 | * @return bytes of the file 205 | */ 206 | public static byte[] getBytesFromAssets(Context context, String fileName) { 207 | InputStream stream = null; 208 | byte[] buffer = null; 209 | try { 210 | stream = context.getAssets().open(fileName); 211 | int size = stream.available(); 212 | buffer = new byte[size]; 213 | stream.read(buffer); 214 | } catch (IOException e) { 215 | e.printStackTrace(); 216 | } finally { 217 | if (stream != null) { 218 | try { 219 | stream.close(); 220 | stream = null; 221 | } catch (IOException e) { 222 | e.printStackTrace(); 223 | } 224 | 225 | } 226 | } 227 | return buffer; 228 | } 229 | 230 | /** 231 | * get bytes of the file from raw folder 232 | * 233 | * @param context 234 | * @param rawId rawId 235 | * @return bytes of file 236 | */ 237 | public static byte[] getBytesFromRaw(Context context, int rawId) { 238 | InputStream is = null; 239 | byte[] buffer = null; 240 | try { 241 | is = context.getResources().openRawResource(rawId); 242 | int size = is.available(); 243 | buffer = new byte[size]; 244 | is.read(buffer); 245 | } catch (IOException e) { 246 | e.printStackTrace(); 247 | } finally { 248 | if (is != null) { 249 | try { 250 | is.close(); 251 | is = null; 252 | } catch (IOException e) { 253 | e.printStackTrace(); 254 | } 255 | } 256 | } 257 | return buffer; 258 | } 259 | 260 | } 261 | -------------------------------------------------------------------------------- /application/src/main/java/com/hwangjr/utils/application/ShortCutHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.application; 2 | 3 | import android.app.Activity; 4 | import android.content.ComponentName; 5 | import android.content.ContentResolver; 6 | import android.content.Intent; 7 | import android.content.Intent.ShortcutIconResource; 8 | import android.database.Cursor; 9 | import android.net.Uri; 10 | 11 | import com.hwangjr.utils.common.R; 12 | 13 | /** 14 | * 创建删除快捷图标 15 | * 16 | * @author jingle1267@163.com 17 | * 需要权限: com.android.launcher.permission.INSTALL_SHORTCUT com.android.launcher.permission.UNINSTALL_SHORTCUT 18 | */ 19 | public class ShortCutHelper { 20 | /** 21 | * Don't let anyone instantiate this class. 22 | */ 23 | private ShortCutHelper() { 24 | throw new Error("Do not need instantiate!"); 25 | } 26 | 27 | /** 28 | * 检测是否存在快捷键 29 | * 30 | * @param activity Activity 31 | * @return 是否存在桌面图标 32 | */ 33 | public static boolean hasShortcut(Activity activity) { 34 | boolean isInstallShortcut = false; 35 | final ContentResolver cr = activity.getContentResolver(); 36 | final String AUTHORITY = "com.android.launcher.settings"; 37 | final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY 38 | + "/favorites?notify=true"); 39 | Cursor c = cr.query(CONTENT_URI, 40 | new String[]{"title", "iconResource"}, "title=?", 41 | new String[]{activity.getString(R.string.app_name).trim()}, 42 | null); 43 | if (c != null && c.getCount() > 0) { 44 | isInstallShortcut = true; 45 | } 46 | return isInstallShortcut; 47 | } 48 | 49 | /** 50 | * 为程序创建桌面快捷方式 51 | * 52 | * @param activity Activity 53 | * @param res res 54 | */ 55 | public static void addShortcut(Activity activity, int res) { 56 | 57 | Intent shortcut = new Intent( 58 | "com.android.launcher.action.INSTALL_SHORTCUT"); 59 | // 快捷方式的名称 60 | shortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME, 61 | activity.getString(R.string.app_name)); 62 | shortcut.putExtra("duplicate", false); // 不允许重复创建 63 | Intent shortcutIntent = new Intent(Intent.ACTION_MAIN); 64 | shortcutIntent.setClassName(activity, activity.getClass().getName()); 65 | shortcut.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); 66 | // 快捷方式的图标 67 | ShortcutIconResource iconRes = Intent.ShortcutIconResource.fromContext( 68 | activity, res); 69 | shortcut.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconRes); 70 | 71 | activity.sendBroadcast(shortcut); 72 | } 73 | 74 | /** 75 | * 删除程序的快捷方式 76 | * 77 | * @param activity Activity 78 | */ 79 | public static void delShortcut(Activity activity) { 80 | 81 | Intent shortcut = new Intent( 82 | "com.android.launcher.action.UNINSTALL_SHORTCUT"); 83 | // 快捷方式的名称 84 | shortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME, 85 | activity.getString(R.string.app_name)); 86 | String appClass = activity.getPackageName() + "." 87 | + activity.getLocalClassName(); 88 | ComponentName comp = new ComponentName(activity.getPackageName(), 89 | appClass); 90 | shortcut.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent( 91 | Intent.ACTION_MAIN).setComponent(comp)); 92 | activity.sendBroadcast(shortcut); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /application/src/main/java/com/hwangjr/utils/application/ViewHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.application; 2 | 3 | import android.content.res.ColorStateList; 4 | import android.graphics.Color; 5 | import android.graphics.ColorMatrix; 6 | import android.graphics.ColorMatrixColorFilter; 7 | import android.graphics.drawable.Drawable; 8 | import android.os.Build; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ImageView; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | public class ViewHelper { 17 | 18 | private ViewHelper() { 19 | throw new AssertionError(); 20 | } 21 | 22 | /** 23 | * get descended views from parent. 24 | * 25 | * @param type of the view 26 | * @param parent ViewGroup 27 | * @param filter Type of views which will be returned. 28 | * @param includeSubClass Whether returned list will include views which are subclass of filter or not. 29 | * @return View 30 | */ 31 | public static List getDescendants(ViewGroup parent, Class filter, boolean includeSubClass) { 32 | List descendedViewList = new ArrayList<>(); 33 | int childCount = parent.getChildCount(); 34 | for (int i = 0; i < childCount; i++) { 35 | View child = parent.getChildAt(i); 36 | Class childClass = child.getClass(); 37 | if ((includeSubClass && filter.isAssignableFrom(childClass)) 38 | || (!includeSubClass && childClass == filter)) { 39 | descendedViewList.add(filter.cast(child)); 40 | } 41 | if (child instanceof ViewGroup) { 42 | descendedViewList.addAll(getDescendants((ViewGroup) child, filter, includeSubClass)); 43 | } 44 | } 45 | return descendedViewList; 46 | } 47 | 48 | /** 49 | * set view background drawable 50 | * 51 | * @param view 52 | * @param drawable 53 | */ 54 | public static void setBackgroundDrawable(View view, Drawable drawable) { 55 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 56 | view.setBackgroundDrawable(drawable); 57 | } else { 58 | view.setBackground(drawable); 59 | } 60 | } 61 | 62 | /** 63 | * get view measured height, it will calculate view and return height 64 | * 65 | * @param view 66 | * @return 67 | */ 68 | public static int getViewMeasuredHeight(View view) { 69 | calcViewMeasure(view); 70 | return view.getMeasuredHeight(); 71 | } 72 | 73 | /** 74 | * get view measured width, it will calculate view and return width 75 | * 76 | * @param view 77 | * @return 78 | */ 79 | public static int getViewMeasuredWidth(View view) { 80 | calcViewMeasure(view); 81 | return view.getMeasuredWidth(); 82 | } 83 | 84 | /** 85 | * measure the view 86 | */ 87 | public static void calcViewMeasure(View view) { 88 | int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 89 | int expandSpec = View.MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST); 90 | view.measure(width, expandSpec); 91 | } 92 | 93 | /** 94 | * change image view brightness by color filter 95 | */ 96 | public static void changeBrightness(ImageView imageview, float brightness) { 97 | imageview.setColorFilter(getBrightnessMatrixColorFilter(brightness)); 98 | } 99 | 100 | /** 101 | * change drawable brightness by color filter 102 | */ 103 | public static void changeBrightness(Drawable drawable, float brightness) { 104 | drawable.setColorFilter(getBrightnessMatrixColorFilter(brightness)); 105 | } 106 | 107 | private static ColorMatrixColorFilter getBrightnessMatrixColorFilter(float brightness) { 108 | ColorMatrix matrix = new ColorMatrix(); 109 | matrix.set( 110 | new float[]{ 111 | 1, 0, 0, 0, brightness, 112 | 0, 1, 0, 0, brightness, 113 | 0, 0, 1, 0, brightness, 114 | 0, 0, 0, 1, 0 115 | }); 116 | return new ColorMatrixColorFilter(matrix); 117 | } 118 | 119 | /** 120 | * get color state list 121 | */ 122 | public static ColorStateList createColorStateList(int normal, int pressed) { 123 | return createColorStateList(normal, pressed, Color.GRAY); 124 | } 125 | 126 | /** 127 | * get color state list 128 | */ 129 | public static ColorStateList createColorStateList(int normal, int pressed, int unable) { 130 | return createColorStateList(normal, pressed, pressed, pressed, unable); 131 | } 132 | 133 | /** 134 | * get color state list 135 | */ 136 | public static ColorStateList createColorStateList(int normal, int pressed, int focused, int checked, int unable) { 137 | int[] colors = new int[]{pressed, focused, checked, normal, unable}; 138 | int[][] states = new int[5][]; 139 | states[0] = new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}; 140 | states[1] = new int[]{android.R.attr.state_focused, android.R.attr.state_enabled}; 141 | states[2] = new int[]{android.R.attr.state_checked, android.R.attr.state_enabled}; 142 | states[3] = new int[]{android.R.attr.state_enabled}; 143 | states[4] = new int[]{}; 144 | return new ColorStateList(states, colors); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /application/src/main/java/com/hwangjr/utils/application/WindowHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.application; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.res.Configuration; 6 | import android.view.Surface; 7 | 8 | public class WindowHelper { 9 | /** 10 | * Don't let anyone instantiate this class. 11 | */ 12 | private WindowHelper() { 13 | throw new Error("Do not need instantiate!"); 14 | } 15 | 16 | /** 17 | * get current window rotation 18 | * 19 | * @param activity activity 20 | * @return int {@link Surface#ROTATION_0}: 0; {@link Surface#ROTATION_90}: 90; 21 | * {@link Surface#ROTATION_180}: 180; {@link Surface#ROTATION_270}: 270 22 | */ 23 | public static int getDisplayRotation(Activity activity) { 24 | switch (activity.getWindowManager().getDefaultDisplay().getRotation()) { 25 | case Surface.ROTATION_0: 26 | return 0; 27 | case Surface.ROTATION_90: 28 | return 90; 29 | case Surface.ROTATION_180: 30 | return 180; 31 | case Surface.ROTATION_270: 32 | return 270; 33 | default: 34 | return 0; 35 | } 36 | } 37 | 38 | /** 39 | * whether current window is landscape 40 | * 41 | * @param context context 42 | * @return boolean true if landscape, otherwise false 43 | */ 44 | public static final boolean isLandscape(Context context) { 45 | return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; 46 | } 47 | 48 | /** 49 | * whether current window is portrait 50 | * 51 | * @param context context 52 | * @return boolean 53 | */ 54 | public static final boolean isPortrait(Context context) { 55 | return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /application/src/test/java/com/hwangjr/utils/application/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.application; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /basic/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /basic/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'checkstyle' 3 | 4 | checkstyle { 5 | toolVersion rootProject.ext.checkstyleVersion 6 | } 7 | 8 | task checkstyle(type: Checkstyle) { 9 | configFile rootProject.file('checkstyle.xml') 10 | source 'src/main/java' 11 | ignoreFailures false 12 | showViolations true 13 | include '**/*.java' 14 | 15 | classpath = files() 16 | } 17 | 18 | afterEvaluate { 19 | if (project.tasks.findByName('check')) { 20 | check.dependsOn('checkstyle') 21 | } 22 | } 23 | 24 | android { 25 | compileSdkVersion rootProject.ext.compileSdkVersion 26 | buildToolsVersion rootProject.ext.buildToolsVersion 27 | 28 | defaultConfig { 29 | minSdkVersion rootProject.ext.minSdkVersion 30 | targetSdkVersion rootProject.ext.targetSdkVersion 31 | consumerProguardFiles 'proguard-rules.pro' 32 | } 33 | } 34 | 35 | dependencies { 36 | testCompile deps.junit 37 | } 38 | 39 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') -------------------------------------------------------------------------------- /basic/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=basic 2 | POM_NAME=Basic 3 | POM_PACKAGING=jar 4 | 5 | #VERSION_NAME=1.0.0-SNAPSHOT -------------------------------------------------------------------------------- /basic/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /basic/src/androidTest/java/com/hwangjr/utils/basic/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.basic; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /basic/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /basic/src/main/java/com/hwangjr/utils/basic/ObjectHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.basic; 2 | 3 | import java.util.Collection; 4 | import java.util.Map; 5 | 6 | /** 7 | * Compare object or convert some types 8 | */ 9 | public class ObjectHelper { 10 | private ObjectHelper() { 11 | throw new AssertionError(); 12 | } 13 | 14 | /** 15 | * compare two object 16 | * 17 | * @param actual 18 | * @param expected 19 | * @return
    20 | *
  • if both are null, return true
  • 21 | *
  • return actual.{@link Object#equals(Object)}
  • 22 | *
23 | */ 24 | public static boolean isEquals(Object actual, Object expected) { 25 | return actual == expected || (actual == null ? expected == null : actual.equals(expected)); 26 | } 27 | 28 | /** 29 | * Object to string 30 | *

31 | *

 32 |      * objectToString(null) = "";
 33 |      * objectToString("") = "";
 34 |      * objectToString("aa") = "aa";
 35 |      * 
36 | * 37 | * @param obj 38 | * @return 39 | */ 40 | public static String objectToString(Object obj) { 41 | return (obj == null ? "" : (obj instanceof String ? (String) obj : obj.toString())); 42 | } 43 | 44 | /** 45 | * convert long array to Long array 46 | * 47 | * @param source 48 | * @return 49 | */ 50 | public static Long[] transformLongArray(long[] source) { 51 | Long[] dest = new Long[source.length]; 52 | for (int i = 0; i < source.length; i++) { 53 | dest[i] = source[i]; 54 | } 55 | return dest; 56 | } 57 | 58 | /** 59 | * convert Long array to long array 60 | * 61 | * @param source 62 | * @return 63 | */ 64 | public static long[] transformLongArray(Long[] source) { 65 | long[] dest = new long[source.length]; 66 | for (int i = 0; i < source.length; i++) { 67 | dest[i] = source[i]; 68 | } 69 | return dest; 70 | } 71 | 72 | /** 73 | * convert int array to Integer array 74 | * 75 | * @param source 76 | * @return 77 | */ 78 | public static Integer[] transformIntArray(int[] source) { 79 | Integer[] dest = new Integer[source.length]; 80 | for (int i = 0; i < source.length; i++) { 81 | dest[i] = source[i]; 82 | } 83 | return dest; 84 | } 85 | 86 | /** 87 | * convert Integer array to int array 88 | * 89 | * @param source 90 | * @return 91 | */ 92 | public static int[] transformIntArray(Integer[] source) { 93 | int[] dest = new int[source.length]; 94 | for (int i = 0; i < source.length; i++) { 95 | dest[i] = source[i]; 96 | } 97 | return dest; 98 | } 99 | 100 | /** 101 | * compare two object 102 | *
    103 | * About result 104 | *
  • if v1 > v2, return 1
  • 105 | *
  • if v1 = v2, return 0
  • 106 | *
  • if v1 < v2, return -1
  • 107 | *
108 | *
    109 | * About rule 110 | *
  • if v1 is null, v2 is null, then return 0
  • 111 | *
  • if v1 is null, v2 is not null, then return -1
  • 112 | *
  • if v1 is not null, v2 is null, then return 1
  • 113 | *
  • return v1.{@link Comparable#compareTo(Object)}
  • 114 | *
115 | * 116 | * @param v1 117 | * @param v2 118 | * @return 119 | */ 120 | public static int compare(V v1, V v2) { 121 | return v1 == null ? (v2 == null ? 0 : -1) : (v2 == null ? 1 : ((Comparable) v1).compareTo(v2)); 122 | } 123 | 124 | /** 125 | * is null or its size is 0 126 | *

127 | *

128 |      * isEmpty(null)   =   true;
129 |      * isEmpty({})     =   true;
130 |      * isEmpty({1})    =   false;
131 |      * 
132 | * 133 | * @param 134 | * @param collection 135 | * @return if collection is null or its size is 0, return true, else return false. 136 | */ 137 | public static boolean isEmpty(Collection collection) { 138 | return null == collection || collection.isEmpty(); 139 | } 140 | 141 | 142 | /** 143 | * is null or its size is 0 144 | * 145 | * @param map 146 | * @param 147 | * @param 148 | * @return if map is null or its size is 0, return true, else return false. 149 | */ 150 | public static boolean isEmpty(Map map) { 151 | return null == map || map.isEmpty(); 152 | } 153 | 154 | /** 155 | * is null or its size is 0 156 | * 157 | * @param objs 158 | * @return if array is null or its size is 0, return true, else return false. 159 | */ 160 | public static boolean isEmpty(Object[] objs) { 161 | return null == objs || objs.length <= 0; 162 | } 163 | 164 | /** 165 | * is null or its size is 0 166 | * 167 | * @param objs 168 | * @return if array is null or its size is 0, return true, else return false. 169 | */ 170 | public static boolean isEmpty(int[] objs) { 171 | return null == objs || objs.length <= 0; 172 | } 173 | 174 | /** 175 | * is null or its length is 0 176 | * 177 | * @param charSequence 178 | * @return if char sequence is null or its length is 0, return true, else return false. 179 | */ 180 | public static boolean isEmpty(CharSequence charSequence) { 181 | return null == charSequence || charSequence.length() <= 0; 182 | } 183 | 184 | /** 185 | * is null 186 | * 187 | * @param obj 188 | * @return if array is null or its size is 0, return true, else return false. 189 | */ 190 | public static boolean isEmpty(Object obj) { 191 | return null == obj; 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /basic/src/test/java/com/hwangjr/utils/basic/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.basic; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | 25 | ext { 26 | minSdkVersion = 9 27 | targetSdkVersion = 23 28 | compileSdkVersion = 23 29 | buildToolsVersion = '23.0.2' 30 | sourceCompatibilityVersion = JavaVersion.VERSION_1_8 31 | targetCompatibilityVersion = JavaVersion.VERSION_1_8 32 | 33 | checkstyleVersion = '6.1.1' 34 | } 35 | 36 | ext.deps = [ 37 | // Test Dependencies 38 | junit : 'junit:junit:4.12', 39 | festassert : 'org.easytesting:fest-assert-core:2.0M10', 40 | festandroid : 'com.squareup:fest-android:1.0.7', 41 | mockitocore : 'org.mockito:mockito-core:1.9.5', 42 | robolectric : 'org.robolectric:robolectric:3.0', 43 | 44 | // Lint Dependencies 45 | lintapi : 'com.android.tools.lint:lint-api:24.3.1', 46 | lintchecks : 'com.android.tools.lint:lint-checks:24.3.1', 47 | 48 | // jetbrains 49 | jbannotations: 'org.jetbrains:annotations:13.0', 50 | 51 | // dependence 52 | gson : 'com.google.code.gson:gson:2.5' 53 | ] -------------------------------------------------------------------------------- /checkstyle.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /collection/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /collection/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'checkstyle' 3 | 4 | checkstyle { 5 | toolVersion rootProject.ext.checkstyleVersion 6 | } 7 | 8 | task checkstyle(type: Checkstyle) { 9 | configFile rootProject.file('checkstyle.xml') 10 | source 'src/main/java' 11 | ignoreFailures false 12 | showViolations true 13 | include '**/*.java' 14 | 15 | classpath = files() 16 | } 17 | 18 | afterEvaluate { 19 | if (project.tasks.findByName('check')) { 20 | check.dependsOn('checkstyle') 21 | } 22 | } 23 | 24 | android { 25 | compileSdkVersion rootProject.ext.compileSdkVersion 26 | buildToolsVersion rootProject.ext.buildToolsVersion 27 | 28 | defaultConfig { 29 | minSdkVersion rootProject.ext.minSdkVersion 30 | targetSdkVersion rootProject.ext.targetSdkVersion 31 | consumerProguardFiles 'proguard-rules.pro' 32 | } 33 | } 34 | 35 | dependencies { 36 | testCompile deps.junit 37 | 38 | compile project(':basic') 39 | } 40 | 41 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') -------------------------------------------------------------------------------- /collection/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=collection 2 | POM_NAME=Collection 3 | POM_PACKAGING=jar 4 | 5 | #VERSION_NAME=1.0.0-SNAPSHOT -------------------------------------------------------------------------------- /collection/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /collection/src/androidTest/java/com/hwangjr/utils/collection/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.collection; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /collection/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /collection/src/main/java/com/hwangjr/utils/collection/ArrayHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.collection; 2 | 3 | import com.hwangjr.utils.basic.ObjectHelper; 4 | 5 | /** 6 | * Array Helper. 7 | */ 8 | public class ArrayHelper { 9 | private ArrayHelper() { 10 | throw new AssertionError(); 11 | } 12 | 13 | /** 14 | * get last element of the target element, before the first one that match the target element front to back 15 | *
    16 | *
  • if array is empty, return defaultValue
  • 17 | *
  • if target element is not exist in array, return defaultValue
  • 18 | *
  • if target element exist in array and its index is not 0, return the last element
  • 19 | *
  • if target element exist in array and its index is 0, return the last one in array if isCircle is true, else 20 | * return defaultValue
  • 21 | *
22 | * 23 | * @param 24 | * @param sourceArray 25 | * @param value value of target element 26 | * @param defaultValue default return value 27 | * @param isCircle whether is circle 28 | * @return 29 | */ 30 | public static V getLast(V[] sourceArray, V value, V defaultValue, boolean isCircle) { 31 | if (ObjectHelper.isEmpty(sourceArray)) { 32 | return defaultValue; 33 | } 34 | 35 | int currentPosition = -1; 36 | for (int i = 0; i < sourceArray.length; i++) { 37 | if (ObjectHelper.isEquals(value, sourceArray[i])) { 38 | currentPosition = i; 39 | break; 40 | } 41 | } 42 | if (currentPosition == -1) { 43 | return defaultValue; 44 | } 45 | 46 | if (currentPosition == 0) { 47 | return isCircle ? sourceArray[sourceArray.length - 1] : defaultValue; 48 | } 49 | return sourceArray[currentPosition - 1]; 50 | } 51 | 52 | /** 53 | * get next element of the target element, after the first one that match the target element front to back 54 | *
    55 | *
  • if array is empty, return defaultValue
  • 56 | *
  • if target element is not exist in array, return defaultValue
  • 57 | *
  • if target element exist in array and not the last one in array, return the next element
  • 58 | *
  • if target element exist in array and the last one in array, return the first one in array if isCircle is 59 | * true, else return defaultValue
  • 60 | *
61 | * 62 | * @param 63 | * @param sourceArray 64 | * @param value value of target element 65 | * @param defaultValue default return value 66 | * @param isCircle whether is circle 67 | * @return 68 | */ 69 | public static V getNext(V[] sourceArray, V value, V defaultValue, boolean isCircle) { 70 | if (ObjectHelper.isEmpty(sourceArray)) { 71 | return defaultValue; 72 | } 73 | 74 | int currentPosition = -1; 75 | for (int i = 0; i < sourceArray.length; i++) { 76 | if (ObjectHelper.isEquals(value, sourceArray[i])) { 77 | currentPosition = i; 78 | break; 79 | } 80 | } 81 | if (currentPosition == -1) { 82 | return defaultValue; 83 | } 84 | 85 | if (currentPosition == sourceArray.length - 1) { 86 | return isCircle ? sourceArray[0] : defaultValue; 87 | } 88 | return sourceArray[currentPosition + 1]; 89 | } 90 | 91 | /** 92 | * @see {@link ArrayHelper#getLast(Object[], Object, Object, boolean)} defaultValue is null 93 | */ 94 | public static V getLast(V[] sourceArray, V value, boolean isCircle) { 95 | return getLast(sourceArray, value, null, isCircle); 96 | } 97 | 98 | /** 99 | * @see {@link ArrayHelper#getNext(Object[], Object, Object, boolean)} defaultValue is null 100 | */ 101 | public static V getNext(V[] sourceArray, V value, boolean isCircle) { 102 | return getNext(sourceArray, value, null, isCircle); 103 | } 104 | 105 | /** 106 | * @see {@link ArrayHelper#getLast(Object[], Object, Object, boolean)} Object is Long 107 | */ 108 | public static long getLast(long[] sourceArray, long value, long defaultValue, boolean isCircle) { 109 | if (sourceArray == null || sourceArray.length <= 0) { 110 | return defaultValue; 111 | } 112 | Long[] array = ObjectHelper.transformLongArray(sourceArray); 113 | return getLast(array, value, defaultValue, isCircle); 114 | 115 | } 116 | 117 | /** 118 | * @see {@link ArrayHelper#getNext(Object[], Object, Object, boolean)} Object is Long 119 | */ 120 | public static long getNext(long[] sourceArray, long value, long defaultValue, boolean isCircle) { 121 | if (sourceArray == null || sourceArray.length <= 0) { 122 | return defaultValue; 123 | } 124 | Long[] array = ObjectHelper.transformLongArray(sourceArray); 125 | return getNext(array, value, defaultValue, isCircle); 126 | } 127 | 128 | /** 129 | * @see {@link ArrayHelper#getLast(Object[], Object, Object, boolean)} Object is Integer 130 | */ 131 | public static int getLast(int[] sourceArray, int value, int defaultValue, boolean isCircle) { 132 | if (sourceArray == null || sourceArray.length <= 0) { 133 | return defaultValue; 134 | } 135 | Integer[] array = ObjectHelper.transformIntArray(sourceArray); 136 | return getLast(array, value, defaultValue, isCircle); 137 | 138 | } 139 | 140 | /** 141 | * @see {@link ArrayHelper#getNext(Object[], Object, Object, boolean)} Object is Integer 142 | */ 143 | public static int getNext(int[] sourceArray, int value, int defaultValue, boolean isCircle) { 144 | if (sourceArray == null || sourceArray.length <= 0) { 145 | return defaultValue; 146 | } 147 | Integer[] array = ObjectHelper.transformIntArray(sourceArray); 148 | return getNext(array, value, defaultValue, isCircle); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /collection/src/main/java/com/hwangjr/utils/collection/CollectionHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.collection; 2 | 3 | import android.text.TextUtils; 4 | 5 | public class CollectionHelper { 6 | /** 7 | * default join separator 8 | **/ 9 | public static final CharSequence DEFAULT_JOIN_SEPARATOR = ","; 10 | 11 | private CollectionHelper() { 12 | throw new AssertionError(); 13 | } 14 | 15 | /** 16 | * join collection to string, separator is {@link #DEFAULT_JOIN_SEPARATOR} 17 | *

18 | *

19 |      * join(null)      =   "";
20 |      * join({})        =   "";
21 |      * join({a,b})     =   "a,b";
22 |      * 
23 | * 24 | * @param collection 25 | * @return join collection to string, separator is {@link #DEFAULT_JOIN_SEPARATOR}. 26 | * if collection is empty, return "" 27 | */ 28 | public static String join(Iterable collection) { 29 | return join(collection, DEFAULT_JOIN_SEPARATOR); 30 | } 31 | 32 | /** 33 | * join list to string 34 | *

35 | *

36 |      * join(null, '#')     =   "";
37 |      * join({}, '#')       =   "";
38 |      * join({a,b,c}, ' ')  =   "abc";
39 |      * join({a,b,c}, '#')  =   "a#b#c";
40 |      * 
41 | * 42 | * @param collection 43 | * @param separator 44 | * @return join list to string. if list is empty, return "" 45 | */ 46 | public static String join(Iterable collection, char separator) { 47 | return join(collection, new String(new char[]{separator})); 48 | } 49 | 50 | /** 51 | * join list to string. if separator is null, use {@link #DEFAULT_JOIN_SEPARATOR} 52 | *

53 | *

54 |      * join(null, "#")     =   "";
55 |      * join({}, "#$")      =   "";
56 |      * join({a,b,c}, null) =   "a,b,c";
57 |      * join({a,b,c}, "")   =   "abc";
58 |      * join({a,b,c}, "#")  =   "a#b#c";
59 |      * join({a,b,c}, "#$") =   "a#$b#$c";
60 |      * 
61 | * 62 | * @param collection 63 | * @param separator 64 | * @return join list to string with separator. if list is empty, return "" 65 | */ 66 | public static String join(Iterable collection, CharSequence separator) { 67 | return collection == null ? "" : TextUtils.join(separator, collection); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /collection/src/main/java/com/hwangjr/utils/collection/CollectionPicker.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.collection; 2 | 3 | import com.hwangjr.utils.basic.ObjectHelper; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collection; 7 | import java.util.List; 8 | 9 | public class CollectionPicker { 10 | 11 | private CollectionPicker() { 12 | throw new AssertionError(); 13 | } 14 | 15 | /** 16 | * get the first element from collection if {@link IPicker#isPicked(Object)} return true 17 | * 18 | * @param expect 19 | * @param collection 20 | * @param 21 | * @return 22 | */ 23 | public static > T pickFirst(T expect, Collection collection) { 24 | if (null == expect || ObjectHelper.isEmpty(collection)) { 25 | return null; 26 | } 27 | T picked = null; 28 | for (T t : collection) { 29 | if (t.isPicked(expect)) { 30 | picked = t; 31 | break; 32 | } 33 | } 34 | return picked; 35 | } 36 | 37 | /** 38 | * get the elements from collection if {@link IPicker#isPicked(Object)} return true 39 | * 40 | * @param expect 41 | * @param collection 42 | * @param 43 | * @return 44 | */ 45 | public static > List pick(T expect, Collection collection) { 46 | if (null == expect || ObjectHelper.isEmpty(collection)) { 47 | return null; 48 | } 49 | List picked = new ArrayList<>(); 50 | for (T t : collection) { 51 | if (t.isPicked(expect)) { 52 | picked.add(t); 53 | } 54 | } 55 | return picked; 56 | } 57 | 58 | /** 59 | * get the first element from collection if {@link IPickerStrategy#isPicked(Object, Object)} return true 60 | * 61 | * @param expect 62 | * @param collection 63 | * @param 64 | * @return 65 | */ 66 | public static T pickFirst(E expect, Collection collection, IPickerStrategy strategy) { 67 | if (null == expect || ObjectHelper.isEmpty(collection)) { 68 | return null; 69 | } 70 | T picked = null; 71 | for (T t : collection) { 72 | if (strategy.isPicked(expect, t)) { 73 | picked = t; 74 | break; 75 | } 76 | } 77 | return picked; 78 | } 79 | 80 | /** 81 | * get the last element from collection if {@link IPickerStrategy#isPicked(Object, Object)} return true 82 | * 83 | * @param expect 84 | * @param collection 85 | * @param 86 | * @return 87 | */ 88 | public static T pickFirstReverse(E expect, List collection, IPickerStrategy strategy) { 89 | if (null == expect || ObjectHelper.isEmpty(collection)) { 90 | return null; 91 | } 92 | T picked = null; 93 | for (int i = collection.size() - 1; i >= 0; i--) { 94 | T t = collection.get(i); 95 | if (strategy.isPicked(expect, t)) { 96 | picked = t; 97 | break; 98 | } 99 | } 100 | return picked; 101 | } 102 | 103 | /** 104 | * get the elements from collection if {@link IPickerStrategy#isPicked(Object, Object)} return true 105 | * 106 | * @param expect 107 | * @param collection 108 | * @param 109 | * @return 110 | */ 111 | public static List pick(E expect, Collection collection, IPickerStrategy strategy) { 112 | if (null == expect || ObjectHelper.isEmpty(collection)) { 113 | return null; 114 | } 115 | if (null == strategy) { 116 | return null; 117 | } 118 | List picked = new ArrayList<>(); 119 | for (T t : collection) { 120 | if (strategy.isPicked(expect, t)) { 121 | picked.add(t); 122 | } 123 | } 124 | return picked; 125 | } 126 | 127 | /** 128 | * picker wrapper 129 | * 130 | * @param 131 | */ 132 | public interface IPicker { 133 | boolean isPicked(T target); 134 | } 135 | 136 | /** 137 | * Picker Strategy 138 | * 139 | * @param 140 | * @param 141 | */ 142 | public interface IPickerStrategy { 143 | boolean isPicked(E expect, T target); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /collection/src/main/java/com/hwangjr/utils/collection/ListHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.collection; 2 | 3 | import com.hwangjr.utils.basic.ObjectHelper; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class ListHelper { 9 | /** 10 | * default join separator 11 | **/ 12 | public static final String DEFAULT_JOIN_SEPARATOR = ","; 13 | 14 | private ListHelper() { 15 | throw new AssertionError(); 16 | } 17 | 18 | /** 19 | * get size of list 20 | *

21 | *

 22 |      * getSize(null)   =   0;
 23 |      * getSize({})     =   0;
 24 |      * getSize({1})    =   1;
 25 |      * 
26 | * 27 | * @param 28 | * @param sourceList 29 | * @return if list is null or empty, return 0, else return {@link List#size()}. 30 | */ 31 | public static int getSize(List sourceList) { 32 | return sourceList == null ? 0 : sourceList.size(); 33 | } 34 | 35 | /** 36 | * compare two list 37 | *

38 | *

 39 |      * isEquals(null, null) = true;
 40 |      * isEquals(new ArrayList<String>(), null) = false;
 41 |      * isEquals(null, new ArrayList<String>()) = false;
 42 |      * isEquals(new ArrayList<String>(), new ArrayList<String>()) = true;
 43 |      * 
44 | * 45 | * @param 46 | * @param actual 47 | * @param expected 48 | * @return 49 | */ 50 | public static boolean isEquals(ArrayList actual, ArrayList expected) { 51 | if (actual == null) { 52 | return expected == null; 53 | } 54 | if (expected == null) { 55 | return false; 56 | } 57 | if (actual.size() != expected.size()) { 58 | return false; 59 | } 60 | 61 | for (int i = 0; i < actual.size(); i++) { 62 | if (!ObjectHelper.isEquals(actual.get(i), expected.get(i))) { 63 | return false; 64 | } 65 | } 66 | return true; 67 | } 68 | 69 | /** 70 | * add distinct entry to list 71 | * 72 | * @param 73 | * @param sourceList 74 | * @param entry 75 | * @return if entry already exist in sourceList, return false, else add it and return true. 76 | */ 77 | public static boolean addDistinctEntry(List sourceList, V entry) { 78 | return (sourceList != null && !sourceList.contains(entry)) ? sourceList.add(entry) : false; 79 | } 80 | 81 | /** 82 | * add all distinct entry to list1 from list2 83 | * 84 | * @param 85 | * @param sourceList 86 | * @param entryList 87 | * @return the count of entries be added 88 | */ 89 | public static int addDistinctList(List sourceList, List entryList) { 90 | if (sourceList == null || ObjectHelper.isEmpty(entryList)) { 91 | return 0; 92 | } 93 | 94 | int sourceCount = sourceList.size(); 95 | for (V entry : entryList) { 96 | if (!sourceList.contains(entry)) { 97 | sourceList.add(entry); 98 | } 99 | } 100 | return sourceList.size() - sourceCount; 101 | } 102 | 103 | /** 104 | * remove duplicate entries in list 105 | * 106 | * @param 107 | * @param sourceList 108 | * @return the count of entries be removed 109 | */ 110 | public static int distinctList(List sourceList) { 111 | if (ObjectHelper.isEmpty(sourceList)) { 112 | return 0; 113 | } 114 | 115 | int sourceCount = sourceList.size(); 116 | int sourceListSize = sourceList.size(); 117 | for (int i = 0; i < sourceListSize; i++) { 118 | for (int j = (i + 1); j < sourceListSize; j++) { 119 | if (sourceList.get(i).equals(sourceList.get(j))) { 120 | sourceList.remove(j); 121 | sourceListSize = sourceList.size(); 122 | j--; 123 | } 124 | } 125 | } 126 | return sourceCount - sourceList.size(); 127 | } 128 | 129 | /** 130 | * add not null entry to list 131 | * 132 | * @param sourceList 133 | * @param value 134 | * @return
    135 | *
  • if sourceList is null, return false
  • 136 | *
  • if value is null, return false
  • 137 | *
  • return {@link List#add(Object)}
  • 138 | *
139 | */ 140 | public static boolean addNotNullValue(List sourceList, V value) { 141 | return (sourceList != null && value != null) ? sourceList.add(value) : false; 142 | } 143 | 144 | /** 145 | * @see {@link ArrayHelper#getLast(Object[], Object, Object, boolean)} defaultValue is null, isCircle is true 146 | */ 147 | public static V getLast(List sourceList, V value) { 148 | return (sourceList == null) ? null : (V) ArrayHelper.getLast(sourceList.toArray(), value, true); 149 | } 150 | 151 | /** 152 | * @see {@link ArrayHelper#getNext(Object[], Object, Object, boolean)} defaultValue is null, isCircle is true 153 | */ 154 | @SuppressWarnings("unchecked") 155 | public static V getNext(List sourceList, V value) { 156 | return (sourceList == null) ? null : (V) ArrayHelper.getNext(sourceList.toArray(), value, true); 157 | } 158 | 159 | /** 160 | * invert list 161 | * 162 | * @param 163 | * @param sourceList 164 | * @return 165 | */ 166 | public static List invertList(List sourceList) { 167 | if (ObjectHelper.isEmpty(sourceList)) { 168 | return sourceList; 169 | } 170 | 171 | List invertList = new ArrayList(sourceList.size()); 172 | for (int i = sourceList.size() - 1; i >= 0; i--) { 173 | invertList.add(sourceList.get(i)); 174 | } 175 | return invertList; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /collection/src/main/java/com/hwangjr/utils/collection/MapHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.collection; 2 | 3 | 4 | import com.hwangjr.utils.basic.ObjectHelper; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.Map.Entry; 9 | 10 | public class MapHelper { 11 | /** 12 | * default separator between key and value 13 | **/ 14 | public static final String DEFAULT_KEY_AND_VALUE_SEPARATOR = ":"; 15 | /** 16 | * default separator between key-value pairs 17 | **/ 18 | public static final String DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR = ","; 19 | 20 | private MapHelper() { 21 | throw new AssertionError(); 22 | } 23 | 24 | /** 25 | * is null or its size is 0 26 | *

27 | *

 28 |      * isEmpty(null)   =   true;
 29 |      * isEmpty({})     =   true;
 30 |      * isEmpty({1, 2})    =   false;
 31 |      * 
32 | * 33 | * @param sourceMap 34 | * @return if map is null or its size is 0, return true, else return false. 35 | */ 36 | public static boolean isEmpty(Map sourceMap) { 37 | return (sourceMap == null || sourceMap.size() == 0); 38 | } 39 | 40 | /** 41 | * add key-value pair to map, and key need not null or empty 42 | * 43 | * @param map 44 | * @param key 45 | * @param value 46 | * @return
    47 | *
  • if map is null, return false
  • 48 | *
  • if key is null or empty, return false
  • 49 | *
  • return {@link Map#put(Object, Object)}
  • 50 | *
51 | */ 52 | public static boolean putNotEmptyKey(Map map, String key, String value) { 53 | if (map == null || ObjectHelper.isEmpty(key)) { 54 | return false; 55 | } 56 | 57 | map.put(key, value); 58 | return true; 59 | } 60 | 61 | /** 62 | * add key-value pair to map, both key and value need not null or empty 63 | * 64 | * @param map 65 | * @param key 66 | * @param value 67 | * @return
    68 | *
  • if map is null, return false
  • 69 | *
  • if key is null or empty, return false
  • 70 | *
  • if value is null or empty, return false
  • 71 | *
  • return {@link Map#put(Object, Object)}
  • 72 | *
73 | */ 74 | public static boolean putNotEmptyKeyAndValue(Map map, String key, String value) { 75 | if (map == null || ObjectHelper.isEmpty(key) || ObjectHelper.isEmpty(value)) { 76 | return false; 77 | } 78 | 79 | map.put(key, value); 80 | return true; 81 | } 82 | 83 | /** 84 | * add key-value pair to map, key need not null or empty 85 | * 86 | * @param map 87 | * @param key 88 | * @param value 89 | * @param defaultValue 90 | * @return
    91 | *
  • if map is null, return false
  • 92 | *
  • if key is null or empty, return false
  • 93 | *
  • if value is null or empty, put defaultValue, return true
  • 94 | *
  • if value is neither null nor empty,put value, return true
  • 95 | *
96 | */ 97 | public static boolean putNotEmptyKeyAndValue(Map map, String key, String value, 98 | String defaultValue) { 99 | if (map == null || ObjectHelper.isEmpty(key)) { 100 | return false; 101 | } 102 | 103 | map.put(key, ObjectHelper.isEmpty(value) ? defaultValue : value); 104 | return true; 105 | } 106 | 107 | /** 108 | * add key-value pair to map, key need not null 109 | * 110 | * @param map 111 | * @param key 112 | * @param value 113 | * @return
    114 | *
  • if map is null, return false
  • 115 | *
  • if key is null, return false
  • 116 | *
  • return {@link Map#put(Object, Object)}
  • 117 | *
118 | */ 119 | public static boolean putNotEmptyKey(Map map, K key, V value) { 120 | if (map == null || key == null) { 121 | return false; 122 | } 123 | 124 | map.put(key, value); 125 | return true; 126 | } 127 | 128 | /** 129 | * add key-value pair to map, both key and value need not null 130 | * 131 | * @param map 132 | * @param key 133 | * @param value 134 | * @return
    135 | *
  • if map is null, return false
  • 136 | *
  • if key is null, return false
  • 137 | *
  • if value is null, return false
  • 138 | *
  • return {@link Map#put(Object, Object)}
  • 139 | *
140 | */ 141 | public static boolean putNotEmptyKeyAndValue(Map map, K key, V value) { 142 | if (map == null || key == null || value == null) { 143 | return false; 144 | } 145 | 146 | map.put(key, value); 147 | return true; 148 | } 149 | 150 | /** 151 | * get key by value, match the first entry front to back 152 | *
    153 | * Attentions: 154 | *
  • for HashMap, the order of entry not same to put order, so you may need to use TreeMap
  • 155 | *
156 | * 157 | * @param 158 | * @param map 159 | * @param value 160 | * @return
    161 | *
  • if map is null, return null
  • 162 | *
  • if value exist, return key
  • 163 | *
  • return null
  • 164 | *
165 | */ 166 | public static K getKeyByValue(Map map, V value) { 167 | if (isEmpty(map)) { 168 | return null; 169 | } 170 | 171 | for (Entry entry : map.entrySet()) { 172 | if (ObjectHelper.isEquals(entry.getValue(), value)) { 173 | return entry.getKey(); 174 | } 175 | } 176 | return null; 177 | } 178 | 179 | /** 180 | * parse key-value pairs to map, ignore empty key 181 | *

182 | *

183 |      * parseToMap("","","",true)=null
184 |      * parseToMap(null,"","",true)=null
185 |      * parseToMap("a:b,:","","",true)={(a,b)}
186 |      * parseToMap("a:b,:d","","",true)={(a,b)}
187 |      * parseToMap("a:b,c:d","","",true)={(a,b),(c,d)}
188 |      * parseToMap("a=b, c = d","=",",",true)={(a,b),(c,d)}
189 |      * parseToMap("a=b, c = d","=",",",false)={(a, b),( c , d)}
190 |      * parseToMap("a=b, c=d","=", ",", false)={(a,b),( c,d)}
191 |      * parseToMap("a=b; c=d","=", ";", false)={(a,b),( c,d)}
192 |      * parseToMap("a=b, c=d", ",", ";", false)={(a=b, c=d)}
193 |      * 
194 | * 195 | * @param source key-value pairs 196 | * @param keyAndValueSeparator separator between key and value 197 | * @param keyAndValuePairSeparator separator between key-value pairs 198 | * @param ignoreSpace whether ignore space at the begging or end of key and value 199 | * @return 200 | */ 201 | public static Map parseToMap(String source, String keyAndValueSeparator, 202 | String keyAndValuePairSeparator, boolean ignoreSpace) { 203 | if (ObjectHelper.isEmpty(source)) { 204 | return null; 205 | } 206 | 207 | if (ObjectHelper.isEmpty(keyAndValueSeparator)) { 208 | keyAndValueSeparator = DEFAULT_KEY_AND_VALUE_SEPARATOR; 209 | } 210 | if (ObjectHelper.isEmpty(keyAndValuePairSeparator)) { 211 | keyAndValuePairSeparator = DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR; 212 | } 213 | Map keyAndValueMap = new HashMap<>(); 214 | String[] keyAndValueArray = source.split(keyAndValuePairSeparator); 215 | if (keyAndValueArray == null) { 216 | return null; 217 | } 218 | 219 | for (String valueEntity : keyAndValueArray) { 220 | if (!ObjectHelper.isEmpty(valueEntity)) { 221 | int separatorIndex = valueEntity.indexOf(keyAndValueSeparator); 222 | if (separatorIndex != -1) { 223 | if (ignoreSpace) { 224 | putNotEmptyKey(keyAndValueMap, valueEntity.substring(0, separatorIndex).trim(), 225 | valueEntity.substring(separatorIndex + 1).trim()); 226 | } else { 227 | putNotEmptyKey(keyAndValueMap, valueEntity.substring(0, separatorIndex), 228 | valueEntity.substring(separatorIndex + 1)); 229 | } 230 | } 231 | } 232 | } 233 | return keyAndValueMap; 234 | } 235 | 236 | /** 237 | * parse key-value pairs to map, ignore empty key 238 | * 239 | * @param source key-value pairs 240 | * @param ignoreSpace whether ignore space at the begging or end of key and value 241 | * @return 242 | * @see {@link #parseToMap(String, String, String, boolean)}, keyAndValueSeparator is 243 | * {@link #DEFAULT_KEY_AND_VALUE_SEPARATOR}, keyAndValuePairSeparator is 244 | * {@link #DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR} 245 | */ 246 | public static Map parseToMap(String source, boolean ignoreSpace) { 247 | return parseToMap(source, DEFAULT_KEY_AND_VALUE_SEPARATOR, DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR, ignoreSpace); 248 | } 249 | 250 | /** 251 | * parse key-value pairs to map, ignore empty key, ignore space at the begging or end of key and value 252 | * 253 | * @param source key-value pairs 254 | * @return 255 | * @see {@link #parseToMap(String, String, String, boolean)}, keyAndValueSeparator is 256 | * {@link #DEFAULT_KEY_AND_VALUE_SEPARATOR}, keyAndValuePairSeparator is 257 | * {@link #DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR}, ignoreSpace is true 258 | */ 259 | public static Map parseToMap(String source) { 260 | return parseToMap(source, DEFAULT_KEY_AND_VALUE_SEPARATOR, DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR, true); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /collection/src/test/java/com/hwangjr/utils/collection/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.collection; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /debug/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /debug/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 9 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | testCompile 'junit:junit:4.12' 24 | compile 'com.android.support:appcompat-v7:23.1.1' 25 | } 26 | -------------------------------------------------------------------------------- /debug/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /debug/src/androidTest/java/com/hwangjr/utils/debug/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.debug; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /debug/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /debug/src/main/java/com/hwangjr/utils/debug/AppWatcher.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.debug; 2 | 3 | import android.app.Activity; 4 | import android.app.ActivityManager; 5 | import android.app.ActivityManager.MemoryInfo; 6 | import android.content.Context; 7 | import android.util.Log; 8 | 9 | import java.util.Timer; 10 | import java.util.TimerTask; 11 | 12 | /** 13 | * watch app health 14 | */ 15 | public class AppWatcher { 16 | 17 | private static AppWatcher sInstance = new AppWatcher(); 18 | 19 | private Context mContext; 20 | private Timer mTimer; 21 | private TimerTask mTimerTask; 22 | 23 | private AppWatcher() { 24 | } 25 | 26 | public static AppWatcher getInstance() { 27 | return sInstance; 28 | } 29 | 30 | /** 31 | * Reference the context, must be application context 32 | * 33 | * @param context 34 | */ 35 | public static void init(Context context) { 36 | sInstance.mContext = context; 37 | } 38 | 39 | /** 40 | * watch for memory usage and heap size per seconds 41 | */ 42 | public void run() { 43 | mTimerTask = new TimerTask() { 44 | @Override 45 | public void run() { 46 | MemoryInfo memoryInfo = new MemoryInfo(); 47 | ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Activity.ACTIVITY_SERVICE); 48 | activityManager.getMemoryInfo(memoryInfo); 49 | Runtime runtime = Runtime.getRuntime(); 50 | String msg = String.format("free:%s%% %sKB total:%sKB max:%sKB ", runtime.freeMemory() * 100f / runtime.totalMemory(), 51 | runtime.freeMemory(), runtime.totalMemory() / 1024, runtime.maxMemory() / 1024); 52 | msg += String.format("native: free:%sKB total:%sKB max:%sKB", android.os.Debug.getNativeHeapFreeSize() / 1024, 53 | android.os.Debug.getNativeHeapAllocatedSize() / 1024, android.os.Debug.getNativeHeapSize() / 1024); 54 | msg += String.format("| availMem:%sKB", memoryInfo.availMem / 1024); 55 | Log.d("memory", msg); 56 | } 57 | }; 58 | mTimer = new Timer(); 59 | mTimer.schedule(mTimerTask, 1000, 1000); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /debug/src/main/java/com/hwangjr/utils/debug/StrictModeHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.debug; 2 | 3 | import android.os.Build; 4 | import android.os.StrictMode; 5 | 6 | public class StrictModeHelper { 7 | 8 | /** 9 | * enable strict mode 10 | *
11 | * Usage: 12 | * if (BuildConfig.DEBUG) { 13 | * StrictModeHelper.enableStrictMode(); 14 | * } 15 | */ 16 | public static void enableStrictMode() { 17 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { 18 | StrictMode.ThreadPolicy.Builder threadPolicyBuilder = new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog(); 19 | StrictMode.VmPolicy.Builder vmPolicyBuilder = new StrictMode.VmPolicy.Builder().detectAll().penaltyLog(); 20 | 21 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 22 | threadPolicyBuilder.penaltyFlashScreen().penaltyDeathOnNetwork(); 23 | } 24 | StrictMode.setThreadPolicy(threadPolicyBuilder.build()); 25 | StrictMode.setVmPolicy(vmPolicyBuilder.build()); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /debug/src/test/java/com/hwangjr/utils/debug/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.debug; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | GROUP=com.hwangjr.utils 2 | VERSION_NAME=1.0.4-SNAPSHOT 3 | 4 | POM_DESCRIPTION=Common Tools For Android Developer. 5 | 6 | POM_URL=https://github.com/AndroidKnife/Utils 7 | POM_SCM_URL=https://github.com/AndroidKnife/Utils 8 | POM_SCM_CONNECTION=scm:git:git://github.com/AndroidKnife/Utils.git 9 | POM_SCM_DEV_CONNECTION=scm:git:git://github.com/AndroidKnife/Utils.git 10 | 11 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 12 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 13 | POM_LICENCE_DIST=repo 14 | 15 | POM_DEVELOPER_ID=hwangjr 16 | POM_DEVELOPER_NAME=HwangJR -------------------------------------------------------------------------------- /gradle/gradle-mvn-push.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Chris Banes 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply plugin: 'maven' 18 | apply plugin: 'signing' 19 | 20 | def isReleaseBuild() { 21 | return VERSION_NAME.contains("SNAPSHOT") == false 22 | } 23 | 24 | def getReleaseRepositoryUrl() { 25 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL 26 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 27 | } 28 | 29 | def getSnapshotRepositoryUrl() { 30 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL 31 | : "https://oss.sonatype.org/content/repositories/snapshots/" 32 | } 33 | 34 | def getRepositoryUsername() { 35 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" 36 | } 37 | 38 | def getRepositoryPassword() { 39 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" 40 | } 41 | 42 | afterEvaluate { project -> 43 | uploadArchives { 44 | repositories { 45 | mavenDeployer { 46 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 47 | 48 | pom.groupId = GROUP 49 | pom.artifactId = POM_ARTIFACT_ID 50 | pom.version = VERSION_NAME 51 | 52 | repository(url: getReleaseRepositoryUrl()) { 53 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 54 | } 55 | snapshotRepository(url: getSnapshotRepositoryUrl()) { 56 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 57 | } 58 | 59 | pom.project { 60 | name POM_NAME 61 | packaging POM_PACKAGING 62 | description POM_DESCRIPTION 63 | url POM_URL 64 | 65 | scm { 66 | url POM_SCM_URL 67 | connection POM_SCM_CONNECTION 68 | developerConnection POM_SCM_DEV_CONNECTION 69 | } 70 | 71 | licenses { 72 | license { 73 | name POM_LICENCE_NAME 74 | url POM_LICENCE_URL 75 | distribution POM_LICENCE_DIST 76 | } 77 | } 78 | 79 | developers { 80 | developer { 81 | id POM_DEVELOPER_ID 82 | name POM_DEVELOPER_NAME 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | 90 | signing { 91 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } 92 | sign configurations.archives 93 | } 94 | 95 | task androidJavadocs(type: Javadoc) { 96 | source = android.sourceSets.main.java.srcDirs 97 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 98 | 99 | if (JavaVersion.current().isJava8Compatible()) { 100 | allprojects { 101 | tasks.withType(Javadoc) { 102 | options.addStringOption('Xdoclint:none', '-quiet') 103 | } 104 | } 105 | } 106 | } 107 | 108 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { 109 | classifier = 'javadoc' 110 | from androidJavadocs.destinationDir 111 | } 112 | 113 | task androidSourcesJar(type: Jar) { 114 | classifier = 'sources' 115 | from android.sourceSets.main.java.sourceFiles 116 | } 117 | 118 | artifacts { 119 | archives androidSourcesJar 120 | archives androidJavadocsJar 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidKnife/Utils/1cb05584faddd96a52d0970f24527f9ce0c22702/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /json/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /json/README.md: -------------------------------------------------------------------------------- 1 | json 2 | ------ 3 | 4 | There are so many json libraries to parse json, like [google/gson](https://github.com/google/gson), [alibaba/fastjson](https://github.com/alibaba/fastjson), [FasterXML/jackson](https://github.com/FasterXML/jackson), etc.. 5 | 6 | so why this library can exist? For 3 reasons: 7 | 1. Light, just two files [[Utils/JSONResolver.java](https://github.com/AndroidKnife/Utils/blob/master/json/src/main/java/com/hwangjr/utils/json/JSONResolver.java), [Utils/JSONNode.java](https://github.com/AndroidKnife/Utils/blob/master/json/src/main/java/com/hwangjr/utils/json/JSONNode.java)] to parse json, **suitable for `sdk` etc..** 8 | 2. Easy to use, use annotation to parse json 9 | 3. Less is more, focus on parse json, just it. 10 | 11 | This library provide: 12 | 1. Light json parse library, just two file: [[Utils/JSONResolver.java](https://github.com/AndroidKnife/Utils/blob/master/json/src/main/java/com/hwangjr/utils/json/JSONResolver.java), [Utils/JSONNode.java](https://github.com/AndroidKnife/Utils/blob/master/json/src/main/java/com/hwangjr/utils/json/JSONNode.java)] 13 | 2. [Utils/JSONGetter.java](https://github.com/AndroidKnife/Utils/blob/master/json/src/main/java/com/hwangjr/utils/json/JSONGetter.java) is an utility to get value from json object 14 | 3. [Utils/GSONWrapper.java at master · AndroidKnife/Utils](https://github.com/AndroidKnife/Utils/blob/master/json/src/main/java/com/hwangjr/utils/json/GSONWrapper.java) is an wrapper of gson, add JSONNode support 15 | 16 | That's all! Enjoy it! 17 | 18 | Usage 19 | ----- 20 | 21 | This is just an utilities, so just call the function. 22 | 23 | More 24 | ------ 25 | 1. [google/gson](https://github.com/google/gson) 26 | 2. [alibaba/fastjson](https://github.com/alibaba/fastjson) 27 | 3. [FasterXML/jackson](https://github.com/FasterXML/jackson) -------------------------------------------------------------------------------- /json/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'checkstyle' 3 | 4 | checkstyle { 5 | toolVersion rootProject.ext.checkstyleVersion 6 | } 7 | 8 | task checkstyle(type: Checkstyle) { 9 | configFile rootProject.file('checkstyle.xml') 10 | source 'src/main/java' 11 | ignoreFailures false 12 | showViolations true 13 | include '**/*.java' 14 | 15 | classpath = files() 16 | } 17 | 18 | afterEvaluate { 19 | if (project.tasks.findByName('check')) { 20 | check.dependsOn('checkstyle') 21 | } 22 | } 23 | 24 | android { 25 | compileSdkVersion rootProject.ext.compileSdkVersion 26 | buildToolsVersion rootProject.ext.buildToolsVersion 27 | 28 | defaultConfig { 29 | minSdkVersion rootProject.ext.minSdkVersion 30 | targetSdkVersion rootProject.ext.targetSdkVersion 31 | consumerProguardFiles 'proguard-rules.pro' 32 | } 33 | } 34 | 35 | dependencies { 36 | testCompile deps.junit 37 | 38 | provided deps.gson 39 | compile project(':basic') 40 | compile project(':collection') 41 | } 42 | 43 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') -------------------------------------------------------------------------------- /json/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=json 2 | POM_NAME=JSON 3 | POM_PACKAGING=aar 4 | 5 | #VERSION_NAME=1.0.1-SNAPSHOT -------------------------------------------------------------------------------- /json/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -keepattributes *Annotation*,*Exceptions*,Signature -------------------------------------------------------------------------------- /json/src/androidTest/java/com/hwangjr/utils/json/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.json; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /json/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /json/src/main/java/com/hwangjr/utils/json/GSONWrapper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.json; 2 | 3 | import com.google.gson.ExclusionStrategy; 4 | import com.google.gson.FieldAttributes; 5 | import com.google.gson.FieldNamingStrategy; 6 | import com.google.gson.Gson; 7 | import com.google.gson.GsonBuilder; 8 | 9 | import java.lang.reflect.Field; 10 | import java.lang.reflect.Type; 11 | 12 | /** 13 | * Wrapper of Gson. 14 | */ 15 | public class GSONWrapper { 16 | 17 | private Gson mGson; 18 | 19 | /** 20 | * Build the default gson. 21 | * This will set the field name strategy to {@link JFieldNamingStrategy} and 22 | * exclusion strategy to {@link JExclusionStrategy} 23 | * 24 | * @return gson 25 | */ 26 | public static Gson buildGson() { 27 | GsonBuilder builder = new GsonBuilder().setFieldNamingStrategy( 28 | new JFieldNamingStrategy()).setExclusionStrategies( 29 | new JExclusionStrategy()); 30 | Gson gson = builder.create(); 31 | return gson; 32 | } 33 | 34 | public synchronized Gson getGson() { 35 | if (mGson == null) { 36 | mGson = buildGson(); 37 | } 38 | return mGson; 39 | } 40 | 41 | /** 42 | * convert object to json string. 43 | * 44 | * @param src object 45 | * @return string of json 46 | */ 47 | public String toJson(Object src) { 48 | return getGson().toJson(src); 49 | } 50 | 51 | /** 52 | * convert json string to the object. 53 | * 54 | * @param json json string 55 | * @param clazz object 56 | * @param 57 | * @return 58 | */ 59 | public T fromJson(String json, Class clazz) { 60 | return getGson().fromJson(json, clazz); 61 | } 62 | 63 | /** 64 | * convert json string to the object. 65 | * 66 | * @param json json string 67 | * @param type type of object 68 | * @param 69 | * @return 70 | */ 71 | public T fromJson(String json, Type type) { 72 | return getGson().fromJson(json, type); 73 | } 74 | 75 | private static class JFieldNamingStrategy implements FieldNamingStrategy { 76 | 77 | @Override 78 | public String translateName(Field f) { 79 | JSONNode colunmInfo = f.getAnnotation(JSONNode.class); 80 | if (colunmInfo != null) { 81 | return colunmInfo.key(); 82 | } 83 | return f.getName(); 84 | } 85 | } 86 | 87 | private static class JExclusionStrategy implements ExclusionStrategy { 88 | 89 | @Override 90 | public boolean shouldSkipClass(Class clazz) { 91 | return false; 92 | } 93 | 94 | @Override 95 | public boolean shouldSkipField(FieldAttributes f) { 96 | return f.getAnnotation(JSONNode.class) == null; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /json/src/main/java/com/hwangjr/utils/json/JSONNode.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.json; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * Annotation For JSON. 11 | *
12 | * Key is the json name, desc is the description for the field. 13 | */ 14 | @Target(ElementType.FIELD) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Documented 17 | public @interface JSONNode { 18 | 19 | String key(); 20 | 21 | String desc() default ""; 22 | } -------------------------------------------------------------------------------- /json/src/test/java/com/hwangjr/utils/json/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.json; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /screen/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /screen/README.md: -------------------------------------------------------------------------------- 1 | Screen 2 | ------ 3 | This is a library screen library. 4 | 5 | Usage 6 | ----- 7 | 8 | More 9 | ------ 10 | None -------------------------------------------------------------------------------- /screen/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'checkstyle' 3 | 4 | task checkstyle(type: Checkstyle) { 5 | configFile rootProject.file('checkstyle.xml') 6 | source 'src/main/java' 7 | ignoreFailures false 8 | showViolations true 9 | include '**/*.java' 10 | 11 | classpath = files() 12 | } 13 | 14 | afterEvaluate { 15 | if (project.tasks.findByName('check')) { 16 | check.dependsOn('checkstyle') 17 | } 18 | } 19 | 20 | android { 21 | compileSdkVersion rootProject.ext.compileSdkVersion 22 | buildToolsVersion rootProject.ext.buildToolsVersion 23 | 24 | defaultConfig { 25 | minSdkVersion rootProject.ext.minSdkVersion 26 | targetSdkVersion rootProject.ext.targetSdkVersion 27 | consumerProguardFiles 'proguard-rules.pro' 28 | } 29 | } 30 | 31 | dependencies { 32 | } 33 | 34 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') -------------------------------------------------------------------------------- /screen/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=screen 2 | POM_NAME=Screen 3 | POM_PACKAGING=aar 4 | 5 | #VERSION_NAME=1.0.0-SNAPSHOT -------------------------------------------------------------------------------- /screen/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /screen/src/androidTest/java/com/hwangjr/utils/screen/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.screen; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /screen/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /screen/src/main/java/com/hwangjr/utils/screen/DensityConverter.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.screen; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | 6 | /** 7 | * Utility to convert density. 8 | */ 9 | public class DensityConverter { 10 | 11 | /** 12 | * convert pixel to dp 13 | */ 14 | public static int px2dp(Context context, float pxValue) { 15 | float scale = context.getResources().getDisplayMetrics().density; 16 | return (int) (pxValue / scale + 0.5f); 17 | } 18 | 19 | /** 20 | * convert dp to px 21 | */ 22 | public static int dp2px(Context context, float dpValue) { 23 | float scale = context.getResources().getDisplayMetrics().density; 24 | return (int) (dpValue * scale + 0.5f); 25 | } 26 | 27 | /** 28 | * convert px to sp 29 | */ 30 | public static int px2sp(Context context, float pxValue) { 31 | float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 32 | return (int) (pxValue / fontScale + 0.5f); 33 | } 34 | 35 | /** 36 | * convert sp to px 37 | */ 38 | public static int sp2px(Context context, float spValue) { 39 | float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 40 | return (int) (spValue * fontScale + 0.5f); 41 | } 42 | 43 | /** 44 | * get screen density. {@link DisplayMetrics#density} 45 | */ 46 | public static float getDensity(Context context) { 47 | DisplayMetrics dm = context.getResources().getDisplayMetrics(); 48 | return dm.density; 49 | } 50 | 51 | /** 52 | * get scaled density.{@link DisplayMetrics#scaledDensity} 53 | * 54 | * @param context 55 | * @return 56 | */ 57 | public static float getScaledDensity(Context context) { 58 | DisplayMetrics dm = context.getResources().getDisplayMetrics(); 59 | return dm.scaledDensity; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /screen/src/main/java/com/hwangjr/utils/screen/ScreenHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.screen; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Rect; 6 | import android.util.DisplayMetrics; 7 | import android.view.Display; 8 | import android.view.Window; 9 | import android.view.WindowManager; 10 | 11 | /** 12 | * Utility for screen. 13 | * get the screen width and height, get status bar height etc.. 14 | */ 15 | public class ScreenHelper { 16 | 17 | /** 18 | * get screen width. {@link DisplayMetrics#widthPixels} 19 | */ 20 | public static int getScreenWidth(Context context) { 21 | DisplayMetrics dm = context.getResources().getDisplayMetrics(); 22 | return dm.widthPixels; 23 | } 24 | 25 | /** 26 | * get screen height. {@link DisplayMetrics#heightPixels} 27 | */ 28 | public static int getScreenHeight(Context context) { 29 | DisplayMetrics dm = context.getResources().getDisplayMetrics(); 30 | return dm.heightPixels; 31 | } 32 | 33 | /** 34 | * get device width. {@link Display#getWidth} 35 | */ 36 | public static int getDeviceWidth(Context context) { 37 | WindowManager manager = (WindowManager) context 38 | .getSystemService(Context.WINDOW_SERVICE); 39 | return manager.getDefaultDisplay().getWidth(); 40 | } 41 | 42 | /** 43 | * get device height. {@link Display#getHeight()} 44 | */ 45 | public static int getDeviceHeight(Context context) { 46 | WindowManager manager = (WindowManager) context 47 | .getSystemService(Context.WINDOW_SERVICE); 48 | return manager.getDefaultDisplay().getHeight(); 49 | } 50 | 51 | /** 52 | * get status bar height. 53 | *
54 | * rely on the fact that te status bar is shown at the time you make your computation, 55 | * 56 | * getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) 57 | * this will not work!! 58 | * 59 | * 60 | * @param activity 61 | * @return 62 | */ 63 | public static int getStatusBarHeight(Activity activity) { 64 | Rect frame = new Rect(); 65 | activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); 66 | return frame.top; 67 | } 68 | 69 | /** 70 | * get status bar height from dimension resource called status_bar_height. 71 | * 72 | * @param context 73 | * @return 74 | */ 75 | public static int getStatusBarHeight(Context context) { 76 | int result = 0; 77 | int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); 78 | if (resourceId > 0) { 79 | result = context.getResources().getDimensionPixelSize(resourceId); 80 | } 81 | return result; 82 | } 83 | 84 | /** 85 | * get status bar plus app bar height, just content's({@link Window#ID_ANDROID_CONTENT}) top. 86 | * 87 | * @param activity 88 | * @return 89 | */ 90 | public static int getContentTopHeight(Activity activity) { 91 | return activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop(); 92 | } 93 | 94 | /** 95 | * get app bar height 96 | * 97 | * @param activity 98 | * @return 99 | */ 100 | public static int getAppBarHeight(Activity activity) { 101 | return getContentTopHeight(activity) - getStatusBarHeight((Context) activity); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /screen/src/main/java/com/hwangjr/utils/screen/ScreenShoot.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.screen; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Canvas; 7 | import android.graphics.Picture; 8 | import android.os.Environment; 9 | import android.view.View; 10 | import android.webkit.WebView; 11 | 12 | import java.io.File; 13 | import java.io.FileNotFoundException; 14 | import java.io.FileOutputStream; 15 | import java.io.IOException; 16 | import java.text.SimpleDateFormat; 17 | import java.util.Date; 18 | 19 | /** 20 | * Shoot for activity and view etc.. 21 | */ 22 | public class ScreenShoot { 23 | 24 | /** 25 | * shoot the activity, exclude the status bar. 26 | */ 27 | public static Bitmap shoot(Activity activity) { 28 | View view = activity.getWindow().getDecorView(); 29 | Bitmap drawingCache = getViewDrawableCache(view); 30 | int statusBarHeight = ScreenHelper.getStatusBarHeight(activity); 31 | int width = ScreenHelper.getDeviceWidth(activity); 32 | int height = ScreenHelper.getDeviceHeight(activity); 33 | Bitmap bitmap = Bitmap.createBitmap(drawingCache, 0, statusBarHeight, width, height - statusBarHeight); 34 | view.destroyDrawingCache(); 35 | return bitmap; 36 | } 37 | 38 | /** 39 | * shoot the view 40 | */ 41 | public static Bitmap shoot(View view) { 42 | Bitmap drawingCache = getViewDrawableCache(view); 43 | Bitmap bitmap = Bitmap.createBitmap(drawingCache, 0, 0, drawingCache.getWidth(), drawingCache.getHeight()); 44 | view.destroyDrawingCache(); 45 | return bitmap; 46 | } 47 | 48 | /** 49 | * shoot the web view 50 | */ 51 | public static Bitmap shoot(WebView webView) { 52 | Picture snapShot = webView.capturePicture(); 53 | Bitmap bitmap = Bitmap.createBitmap(snapShot.getWidth(), snapShot.getHeight(), Bitmap.Config.ARGB_8888); 54 | Canvas canvas = new Canvas(bitmap); 55 | snapShot.draw(canvas); 56 | return bitmap; 57 | } 58 | 59 | /** 60 | * get view drawable cache. 61 | * 62 | * Remember to destroy the cache.{@link View#destroyDrawingCache()} 63 | * 64 | */ 65 | private static Bitmap getViewDrawableCache(View view) { 66 | view.setDrawingCacheEnabled(true); 67 | view.buildDrawingCache(); 68 | return view.getDrawingCache(); 69 | } 70 | 71 | /** 72 | * shoot activity and save bitmap to default path. 73 | * if save succeed, it will return the path. 74 | * path : {@link #getDefaultPath(Context)} 75 | */ 76 | public static String shootAndSave(Activity activity) { 77 | String filePath = getDefaultPath(activity); 78 | return saveBitmap(shoot(activity), filePath) ? filePath : ""; 79 | } 80 | 81 | /** 82 | * shoot web view and save bitmap to default path. 83 | * if save succeed, it will return the path. 84 | * path : {@link #getDefaultPath(Context)} 85 | */ 86 | public static String shootAndSave(WebView webView) { 87 | String filePath = getDefaultPath(webView.getContext()); 88 | return saveBitmap(shoot(webView), filePath) ? filePath : ""; 89 | } 90 | 91 | /** 92 | * save the bitmap to path. 93 | */ 94 | public static boolean saveBitmap(Bitmap bitmap, String path) { 95 | FileOutputStream outputStream = null; 96 | try { 97 | outputStream = new FileOutputStream(path); 98 | if (outputStream != null) { 99 | bitmap.compress(Bitmap.CompressFormat.PNG, 90, outputStream); 100 | outputStream.flush(); 101 | outputStream.close(); 102 | outputStream = null; 103 | return true; 104 | } 105 | } catch (FileNotFoundException e) { 106 | e.printStackTrace(); 107 | } catch (IOException e) { 108 | e.printStackTrace(); 109 | } finally { 110 | if (outputStream != null) { 111 | try { 112 | outputStream.close(); 113 | } catch (IOException e) { 114 | e.printStackTrace(); 115 | } 116 | } 117 | } 118 | return false; 119 | } 120 | 121 | /** 122 | * generate the default path for the file. 123 | * default file name format is: yyyyMMddHHmmss.png. 124 | */ 125 | private static String getDefaultPath(Context context) { 126 | String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".png"; 127 | String path = context.getFilesDir() + fileName; 128 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 129 | path = context.getExternalCacheDir() + File.separator + fileName; 130 | } 131 | return path; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /screen/src/test/java/com/hwangjr/utils/screen/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.screen; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':softinput', ':timber', ':json', ':xml', ':archives', ':shell', ':collection', ':basic', ':application', ':templete', ':debug', ':screen', ':animation' 2 | -------------------------------------------------------------------------------- /shell/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /shell/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'checkstyle' 3 | 4 | checkstyle { 5 | toolVersion rootProject.ext.checkstyleVersion 6 | } 7 | 8 | task checkstyle(type: Checkstyle) { 9 | configFile rootProject.file('checkstyle.xml') 10 | source 'src/main/java' 11 | ignoreFailures false 12 | showViolations true 13 | include '**/*.java' 14 | 15 | classpath = files() 16 | } 17 | 18 | afterEvaluate { 19 | if (project.tasks.findByName('check')) { 20 | check.dependsOn('checkstyle') 21 | } 22 | } 23 | 24 | android { 25 | compileSdkVersion rootProject.ext.compileSdkVersion 26 | buildToolsVersion rootProject.ext.buildToolsVersion 27 | 28 | defaultConfig { 29 | minSdkVersion rootProject.ext.minSdkVersion 30 | targetSdkVersion rootProject.ext.targetSdkVersion 31 | consumerProguardFiles 'proguard-rules.pro' 32 | } 33 | } 34 | 35 | dependencies { 36 | testCompile deps.junit 37 | } 38 | 39 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') -------------------------------------------------------------------------------- /shell/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=shell 2 | POM_NAME=Shell 3 | POM_PACKAGING=jar 4 | 5 | #VERSION_NAME=1.0.0-SNAPSHOT -------------------------------------------------------------------------------- /shell/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /shell/src/androidTest/java/com/hwangjr/utils/shell/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.shell; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /shell/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /shell/src/main/java/com/hwangjr/utils/shell/ShellHelper.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.shell; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.DataOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.util.List; 10 | 11 | /** 12 | * Execute Shell For Android. 13 | *
14 | * This utility is used to check root permission or exec command. 15 | * While exec commands, the result will wrapped by {@link CommandResult}. 16 | */ 17 | public class ShellHelper { 18 | public static final String COMMAND_SU = "su"; 19 | public static final String COMMAND_SH = "sh"; 20 | public static final String COMMAND_EXIT = "exit\n"; 21 | public static final String COMMAND_LINE_END = "\n"; 22 | 23 | private ShellHelper() { 24 | throw new AssertionError(); 25 | } 26 | 27 | /** 28 | * check whether has root permission 29 | * 30 | * @return true has root permission, false don't have permission 31 | */ 32 | public static boolean checkRootPermission() { 33 | return exec("echo root", true, false).result == 0; 34 | } 35 | 36 | /** 37 | * execute shell command, default return result msg 38 | * 39 | * @param command command 40 | * @param isRoot whether need to run with root 41 | * @return 42 | * @see ShellHelper#exec(String[], boolean, boolean) 43 | */ 44 | public static CommandResult exec(String command, boolean isRoot) { 45 | return exec(new String[]{command}, isRoot, true); 46 | } 47 | 48 | /** 49 | * execute shell commands, default return result msg 50 | * 51 | * @param commands command list 52 | * @param isRoot whether need to run with root 53 | * @return 54 | * @see ShellHelper#exec(String[], boolean, boolean) 55 | */ 56 | public static CommandResult exec(List commands, boolean isRoot) { 57 | return exec(commands == null ? null : commands.toArray(new String[]{}), isRoot, true); 58 | } 59 | 60 | /** 61 | * execute shell commands, default return result msg 62 | * 63 | * @param commands command array 64 | * @param isRoot whether need to run with root 65 | * @return 66 | * @see ShellHelper#exec(String[], boolean, boolean) 67 | */ 68 | public static CommandResult exec(String[] commands, boolean isRoot) { 69 | return exec(commands, isRoot, true); 70 | } 71 | 72 | /** 73 | * execute shell command 74 | * 75 | * @param command command 76 | * @param isRoot whether need to run with root 77 | * @param isNeedResultMsg whether need result msg 78 | * @return 79 | * @see ShellHelper#exec(String[], boolean, boolean) 80 | */ 81 | public static CommandResult exec(String command, boolean isRoot, boolean isNeedResultMsg) { 82 | return exec(new String[]{command}, isRoot, isNeedResultMsg); 83 | } 84 | 85 | /** 86 | * execute shell commands 87 | * 88 | * @param commands command list 89 | * @param isRoot whether need to run with root 90 | * @param isNeedResultMsg whether need result msg 91 | * @return 92 | * @see ShellHelper#exec(String[], boolean, boolean) 93 | */ 94 | public static CommandResult exec(List commands, boolean isRoot, boolean isNeedResultMsg) { 95 | return exec(commands == null ? null : commands.toArray(new String[]{}), isRoot, isNeedResultMsg); 96 | } 97 | 98 | /** 99 | * execute shell commands 100 | * 101 | * @param commands command array 102 | * @param isRoot whether need to run with root 103 | * @param isNeedResultMsg whether need result msg 104 | * @return
    105 | *
  • if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and 106 | * {@link CommandResult#errorMsg} is null.
  • 107 | *
  • if {@link CommandResult#result} is -1, there maybe some exceptions.
  • 108 | *
109 | */ 110 | public static CommandResult exec(String[] commands, boolean isRoot, boolean isNeedResultMsg) { 111 | int result = -1; 112 | if (commands == null || commands.length == 0) { 113 | return new CommandResult(result, null, null); 114 | } 115 | 116 | Process process = null; 117 | BufferedReader successResult = null; 118 | BufferedReader errorResult = null; 119 | StringBuilder successMsg = null; 120 | StringBuilder errorMsg = null; 121 | DataOutputStream os = null; 122 | 123 | try { 124 | process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH); 125 | os = new DataOutputStream(process.getOutputStream()); 126 | for (String command : commands) { 127 | if (!TextUtils.isEmpty(command)) { 128 | // do not use os.writeBytes(command), avoid chinese charset error 129 | os.write(command.getBytes()); 130 | os.writeBytes(COMMAND_LINE_END); 131 | os.flush(); 132 | } 133 | } 134 | os.writeBytes(COMMAND_EXIT); 135 | os.flush(); 136 | 137 | result = process.waitFor(); 138 | // get command result 139 | if (isNeedResultMsg) { 140 | successMsg = new StringBuilder(); 141 | errorMsg = new StringBuilder(); 142 | successResult = new BufferedReader(new InputStreamReader(process.getInputStream())); 143 | errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream())); 144 | String s; 145 | while ((s = successResult.readLine()) != null) { 146 | successMsg.append(s); 147 | } 148 | while ((s = errorResult.readLine()) != null) { 149 | errorMsg.append(s); 150 | } 151 | } 152 | } catch (IOException e) { 153 | e.printStackTrace(); 154 | } catch (Exception e) { 155 | e.printStackTrace(); 156 | } finally { 157 | try { 158 | if (os != null) { 159 | os.close(); 160 | } 161 | if (successResult != null) { 162 | successResult.close(); 163 | } 164 | if (errorResult != null) { 165 | errorResult.close(); 166 | } 167 | } catch (IOException e) { 168 | e.printStackTrace(); 169 | } 170 | if (process != null) { 171 | process.destroy(); 172 | } 173 | } 174 | return new CommandResult(result, successMsg == null ? null : successMsg.toString(), 175 | errorMsg == null ? null : errorMsg.toString()); 176 | } 177 | 178 | /** 179 | * result of command 180 | *
    181 | *
  • {@link CommandResult#result} means result of command, 0 means normal, else means error, 182 | * same to execute in linux shell
  • 183 | *
  • {@link CommandResult#successMsg} means success message of command result
  • 184 | *
  • {@link CommandResult#errorMsg} means error message of command result
  • 185 | *
186 | */ 187 | public static class CommandResult { 188 | /** 189 | * result of command 190 | **/ 191 | public int result; 192 | /** 193 | * success message of command result 194 | **/ 195 | public String successMsg; 196 | /** 197 | * error message of command result 198 | **/ 199 | public String errorMsg; 200 | 201 | public CommandResult(int result) { 202 | this.result = result; 203 | } 204 | 205 | public CommandResult(int result, String successMsg, String errorMsg) { 206 | this.result = result; 207 | this.successMsg = successMsg; 208 | this.errorMsg = errorMsg; 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /shell/src/test/java/com/hwangjr/utils/shell/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.shell; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /softinput/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /softinput/README.md: -------------------------------------------------------------------------------- 1 | SoftInput 2 | ------ 3 | 4 | SoftInput has many functions to control the soft keyguard show/hide. 5 | -------------------------------------------------------------------------------- /softinput/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'checkstyle' 3 | 4 | task checkstyle(type: Checkstyle) { 5 | configFile rootProject.file('checkstyle.xml') 6 | source 'src/main/java' 7 | ignoreFailures false 8 | showViolations true 9 | include '**/*.java' 10 | 11 | classpath = files() 12 | } 13 | 14 | afterEvaluate { 15 | if (project.tasks.findByName('check')) { 16 | check.dependsOn('checkstyle') 17 | } 18 | } 19 | 20 | android { 21 | compileSdkVersion rootProject.ext.compileSdkVersion 22 | buildToolsVersion rootProject.ext.buildToolsVersion 23 | 24 | defaultConfig { 25 | minSdkVersion rootProject.ext.minSdkVersion 26 | targetSdkVersion rootProject.ext.targetSdkVersion 27 | consumerProguardFiles 'proguard-rules.pro' 28 | } 29 | } 30 | 31 | dependencies { 32 | testCompile deps.junit 33 | } 34 | 35 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') -------------------------------------------------------------------------------- /softinput/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=softinput 2 | POM_NAME=SoftInput 3 | POM_PACKAGING=aar 4 | 5 | #VERSION_NAME=1.0.2-SNAPSHOT -------------------------------------------------------------------------------- /softinput/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /softinput/src/androidTest/java/com/hwangjr/utils/softinput/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.softinput; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /softinput/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /softinput/src/main/java/com/hwangjr/utils/softinput/SoftInput.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.softinput; 2 | 3 | import android.content.Context; 4 | import android.os.IBinder; 5 | import android.os.ResultReceiver; 6 | import android.view.View; 7 | import android.view.inputmethod.InputMethodManager; 8 | 9 | /** 10 | * Show/hide soft keyboard. 11 | */ 12 | public class SoftInput { 13 | 14 | private SoftInput() { 15 | } 16 | 17 | /** 18 | * Show the input method's soft input area, so the user sees the input method window and can interact with it. 19 | * This can only be called from the currently active input method, as validated by the given token. 20 | * 21 | * @param view the current focused view 22 | */ 23 | public static void showSoftInputFromInputMethod(View view) { 24 | if (view != null) { 25 | Context context = view.getContext(); 26 | IBinder windowToken = view.getWindowToken(); 27 | InputMethodManager inputMethodManager = (InputMethodManager) context 28 | .getSystemService(Context.INPUT_METHOD_SERVICE); 29 | inputMethodManager.showSoftInputFromInputMethod(windowToken, 0); 30 | } 31 | } 32 | 33 | /** 34 | * Request to hide the soft input window from the context of the window that is currently accepting input. 35 | * This should be called as a result of the user doing some actually than fairly explicitly requests to have the input window hidden. 36 | * 37 | * @param view the current focused view 38 | */ 39 | public static boolean hideSoftInputFromWindow(View view) { 40 | boolean result = false; 41 | if (view != null) { 42 | Context context = view.getContext(); 43 | IBinder windowToken = view.getWindowToken(); 44 | InputMethodManager inputMethodManager = (InputMethodManager) context 45 | .getSystemService(Context.INPUT_METHOD_SERVICE); 46 | result = inputMethodManager.hideSoftInputFromWindow(windowToken, 0); 47 | } 48 | return result; 49 | } 50 | 51 | /** 52 | * Synonym for {@link InputMethodManager.showSoftInput(View, int, ResultReceiver)} without 53 | * a result receiver: explicitly request that the current input method's 54 | * soft input area be shown to the user, if needed. 55 | * 56 | * @param view the current focused view 57 | */ 58 | public static boolean showSoftInput(View view) { 59 | boolean result = false; 60 | if (view != null) { 61 | InputMethodManager inputMethodManager = (InputMethodManager) view.getContext() 62 | .getSystemService(Context.INPUT_METHOD_SERVICE); 63 | result = inputMethodManager.showSoftInput(view, 0); 64 | } 65 | return result; 66 | } 67 | 68 | /** 69 | * Request to hide the soft input window from the context of the window that is currently accepting input. 70 | * This should be called as a result of the user doing some actually than fairly explicitly requests to have the input window hidden. 71 | * 72 | * @param view the current focused view 73 | */ 74 | public static boolean hideSoftInput(View view) { 75 | return hideSoftInputFromWindow(view); 76 | } 77 | 78 | /** 79 | * This method toggles the input method window display. 80 | * If the input window is already displayed, it gets hidden. If not the input window will be displayed. 81 | * 82 | * @param context context to get the input service 83 | */ 84 | public static void toggle(Context context) { 85 | if (context != null) { 86 | InputMethodManager inputMethodManager = (InputMethodManager) context 87 | .getSystemService(Context.INPUT_METHOD_SERVICE); 88 | inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /softinput/src/test/java/com/hwangjr/utils/softinput/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.softinput; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /templete/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /templete/README.md: -------------------------------------------------------------------------------- 1 | Templete 2 | ------ 3 | This is a library templete. 4 | 5 | Usage 6 | ----- 7 | Copy the files. 8 | 9 | More 10 | ------ 11 | None -------------------------------------------------------------------------------- /templete/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'checkstyle' 3 | 4 | task checkstyle(type: Checkstyle) { 5 | configFile rootProject.file('checkstyle.xml') 6 | source 'src/main/java' 7 | ignoreFailures false 8 | showViolations true 9 | include '**/*.java' 10 | 11 | classpath = files() 12 | } 13 | 14 | afterEvaluate { 15 | if (project.tasks.findByName('check')) { 16 | check.dependsOn('checkstyle') 17 | } 18 | } 19 | 20 | android { 21 | compileSdkVersion rootProject.ext.compileSdkVersion 22 | buildToolsVersion rootProject.ext.buildToolsVersion 23 | 24 | defaultConfig { 25 | minSdkVersion rootProject.ext.minSdkVersion 26 | targetSdkVersion rootProject.ext.targetSdkVersion 27 | consumerProguardFiles 'proguard-rules.pro' 28 | } 29 | } 30 | 31 | dependencies { 32 | } 33 | 34 | //apply from: rootProject.file('gradle/gradle-mvn-push.gradle') -------------------------------------------------------------------------------- /templete/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=templete 2 | POM_NAME=Templete 3 | POM_PACKAGING=aar 4 | 5 | #VERSION_NAME=1.0.0-SNAPSHOT -------------------------------------------------------------------------------- /templete/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /templete/src/androidTest/java/com/hwangjr/utils/templete/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.templete; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /templete/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /templete/src/test/java/com/hwangjr/utils/templete/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.templete; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /timber/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /timber/README.md: -------------------------------------------------------------------------------- 1 | Timber 2 | ------ 3 | 4 | [Timber]((https://github.com/JakeWharton/timber)) is awesome, it can make `Log` to be a happy stuff! 5 | 6 | You also won't miss [Pidcat](http://github.com/JakeWharton/pidcat/) ! 7 | 8 | So, why this library exists: 9 | > JakeWharton ([Minimum SDK · Issue #98 · JakeWharton/timber](https://github.com/JakeWharton/timber/issues/98)) 10 | No one has given a compelling argument other than "because you can". Why 11 | should support be added for this API level no one is using? 12 | 13 | Usage 14 | ----- 15 | 16 | Two easy steps: 17 | 18 | 1. Install any `Tree` instances you want in the `onCreate` of your application class. 19 | 2. Call `Timber`'s static methods everywhere throughout your app. 20 | 21 | Check out the sample app in `timber-sample/` to see it in action. 22 | 23 | More 24 | ------ 25 | 26 | [JakeWharton/timber](https://github.com/JakeWharton/timber) 27 | -------------------------------------------------------------------------------- /timber/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'checkstyle' 3 | 4 | task checkstyle(type: Checkstyle) { 5 | configFile rootProject.file('checkstyle.xml') 6 | source 'src/main/java' 7 | ignoreFailures false 8 | showViolations true 9 | include '**/*.java' 10 | 11 | classpath = files() 12 | } 13 | 14 | afterEvaluate { 15 | if (project.tasks.findByName('check')) { 16 | check.dependsOn('checkstyle') 17 | } 18 | } 19 | 20 | android { 21 | compileSdkVersion rootProject.ext.compileSdkVersion 22 | buildToolsVersion rootProject.ext.buildToolsVersion 23 | 24 | defaultConfig { 25 | minSdkVersion rootProject.ext.minSdkVersion 26 | targetSdkVersion rootProject.ext.targetSdkVersion 27 | consumerProguardFiles 'consumer-proguard-rules.pro' 28 | } 29 | } 30 | 31 | dependencies { 32 | provided deps.jbannotations 33 | 34 | testCompile deps.junit 35 | testCompile deps.festandroid 36 | testCompile deps.festassert 37 | testCompile deps.robolectric 38 | } 39 | 40 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') -------------------------------------------------------------------------------- /timber/consumer-proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -dontwarn org.jetbrains.annotations.** 2 | -------------------------------------------------------------------------------- /timber/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=timber 2 | POM_NAME=Timber 3 | POM_PACKAGING=aar 4 | 5 | VERSION_NAME=4.1.2-SNAPSHOT -------------------------------------------------------------------------------- /timber/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /timber/src/test/java/timber/log/TimberTest.java: -------------------------------------------------------------------------------- 1 | package timber.log; 2 | 3 | import android.util.Log; 4 | 5 | import java.net.UnknownHostException; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.concurrent.CountDownLatch; 10 | import org.junit.After; 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.robolectric.RobolectricTestRunner; 15 | import org.robolectric.annotation.Config; 16 | import org.robolectric.shadows.ShadowLog; 17 | 18 | import static org.fest.assertions.api.Assertions.assertThat; 19 | import static org.junit.Assert.fail; 20 | import static org.robolectric.shadows.ShadowLog.LogItem; 21 | 22 | @RunWith(RobolectricTestRunner.class) // 23 | @Config(manifest = Config.NONE) 24 | public class TimberTest { 25 | @Before @After public void setUpAndTearDown() { 26 | Timber.uprootAll(); 27 | } 28 | 29 | // NOTE: This class references the line number. Keep it at the top so it does not change. 30 | @Test public void debugTreeCanAlterCreatedTag() { 31 | Timber.plant(new Timber.DebugTree() { 32 | @Override protected String createStackElementTag(StackTraceElement element) { 33 | return super.createStackElementTag(element) + ':' + element.getLineNumber(); 34 | } 35 | }); 36 | 37 | Timber.d("Test"); 38 | 39 | assertLog() 40 | .hasDebugMessage("TimberTest:37", "Test") 41 | .hasNoMoreMessages(); 42 | } 43 | 44 | @Test public void recursion() { 45 | Timber.Tree timber = Timber.asTree(); 46 | try { 47 | Timber.plant(timber); 48 | fail(); 49 | } catch (IllegalArgumentException e) { 50 | assertThat(e).hasMessage("Cannot plant Timber into itself."); 51 | } 52 | } 53 | 54 | @Test public void treeCount() { 55 | // inserts trees and checks if the amount of returned trees matches. 56 | assertThat(Timber.treeCount()).isEqualTo(0); 57 | for(int i= 1 ; i < 50 ; i++){ 58 | Timber.plant(new Timber.DebugTree()); 59 | assertThat(Timber.treeCount()).isEqualTo(i); 60 | } 61 | Timber.uprootAll(); 62 | assertThat(Timber.treeCount()).isEqualTo(0); 63 | } 64 | 65 | @Test public void nullTree() { 66 | try { 67 | Timber.plant(null); 68 | fail(); 69 | } catch (NullPointerException e) { 70 | assertThat(e).hasMessage("tree == null"); 71 | } 72 | } 73 | 74 | @Test public void forestReturnsAllPlanted() { 75 | Timber.DebugTree tree1 = new Timber.DebugTree(); 76 | Timber.DebugTree tree2 = new Timber.DebugTree(); 77 | Timber.plant(tree1); 78 | Timber.plant(tree2); 79 | 80 | assertThat(Timber.forest()).containsExactly(tree1, tree2); 81 | } 82 | 83 | @Test public void uprootThrowsIfMissing() { 84 | try { 85 | Timber.uproot(new Timber.DebugTree()); 86 | fail(); 87 | } catch (IllegalArgumentException e) { 88 | assertThat(e).hasMessageStartingWith("Cannot uproot tree which is not planted: "); 89 | } 90 | } 91 | 92 | @Test public void uprootRemovesTree() { 93 | Timber.DebugTree tree1 = new Timber.DebugTree(); 94 | Timber.DebugTree tree2 = new Timber.DebugTree(); 95 | Timber.plant(tree1); 96 | Timber.plant(tree2); 97 | Timber.d("First"); 98 | Timber.uproot(tree1); 99 | Timber.d("Second"); 100 | 101 | assertLog() 102 | .hasDebugMessage("TimberTest", "First") 103 | .hasDebugMessage("TimberTest", "First") 104 | .hasDebugMessage("TimberTest", "Second") 105 | .hasNoMoreMessages(); 106 | } 107 | 108 | @Test public void uprootAllRemovesAll() { 109 | Timber.DebugTree tree1 = new Timber.DebugTree(); 110 | Timber.DebugTree tree2 = new Timber.DebugTree(); 111 | Timber.plant(tree1); 112 | Timber.plant(tree2); 113 | Timber.d("First"); 114 | Timber.uprootAll(); 115 | Timber.d("Second"); 116 | 117 | assertLog() 118 | .hasDebugMessage("TimberTest", "First") 119 | .hasDebugMessage("TimberTest", "First") 120 | .hasNoMoreMessages(); 121 | } 122 | 123 | @Test public void noArgsDoesNotFormat() { 124 | Timber.plant(new Timber.DebugTree()); 125 | Timber.d("te%st"); 126 | 127 | assertLog() 128 | .hasDebugMessage("TimberTest", "te%st") 129 | .hasNoMoreMessages(); 130 | } 131 | 132 | @Test public void debugTreeTagGeneration() { 133 | Timber.plant(new Timber.DebugTree()); 134 | Timber.d("Hello, world!"); 135 | 136 | assertLog() 137 | .hasDebugMessage("TimberTest", "Hello, world!") 138 | .hasNoMoreMessages(); 139 | } 140 | 141 | @Test public void debugTreeTagGenerationStripsAnonymousClassMarker() { 142 | Timber.plant(new Timber.DebugTree()); 143 | new Runnable() { 144 | @Override public void run() { 145 | Timber.d("Hello, world!"); 146 | 147 | new Runnable() { 148 | @Override public void run() { 149 | Timber.d("Hello, world!"); 150 | } 151 | }.run(); 152 | } 153 | }.run(); 154 | 155 | assertLog() 156 | .hasDebugMessage("TimberTest", "Hello, world!") 157 | .hasDebugMessage("TimberTest", "Hello, world!") 158 | .hasNoMoreMessages(); 159 | } 160 | 161 | @Test public void debugTreeCustomTag() { 162 | Timber.plant(new Timber.DebugTree()); 163 | Timber.tag("Custom").d("Hello, world!"); 164 | 165 | assertLog() 166 | .hasDebugMessage("Custom", "Hello, world!") 167 | .hasNoMoreMessages(); 168 | } 169 | 170 | @Test public void messageWithException() { 171 | Timber.plant(new Timber.DebugTree()); 172 | NullPointerException datThrowable = new NullPointerException(); 173 | Timber.e(datThrowable, "OMFG!"); 174 | 175 | assertExceptionLogged("OMFG!", "java.lang.NullPointerException"); 176 | } 177 | 178 | @Test public void exceptionFromSpawnedThread() throws InterruptedException { 179 | Timber.plant(new Timber.DebugTree()); 180 | final NullPointerException datThrowable = new NullPointerException(); 181 | final CountDownLatch latch = new CountDownLatch(1); 182 | new Thread() { 183 | @Override public void run() { 184 | Timber.e(datThrowable, "OMFG!"); 185 | latch.countDown(); 186 | } 187 | }.run(); 188 | latch.await(); 189 | assertExceptionLogged("OMFG!", "java.lang.NullPointerException"); 190 | } 191 | 192 | @Test public void nullMessageWithThrowable() { 193 | Timber.plant(new Timber.DebugTree()); 194 | final NullPointerException datThrowable = new NullPointerException(); 195 | Timber.e(datThrowable, null); 196 | 197 | assertExceptionLogged("", "java.lang.NullPointerException"); 198 | } 199 | 200 | @Test public void chunkAcrossNewlinesAndLimit() { 201 | Timber.plant(new Timber.DebugTree()); 202 | Timber.d(repeat('a', 3000) + '\n' + repeat('b', 6000) + '\n' + repeat('c', 3000)); 203 | 204 | assertLog() 205 | .hasDebugMessage("TimberTest", repeat('a', 3000)) 206 | .hasDebugMessage("TimberTest", repeat('b', 4000)) 207 | .hasDebugMessage("TimberTest", repeat('b', 2000)) 208 | .hasDebugMessage("TimberTest", repeat('c', 3000)) 209 | .hasNoMoreMessages(); 210 | } 211 | 212 | @Test public void nullMessageWithoutThrowable() { 213 | Timber.plant(new Timber.DebugTree()); 214 | Timber.d(null); 215 | 216 | assertLog().hasNoMoreMessages(); 217 | } 218 | 219 | @Test public void logMessageCallback() { 220 | final List logs = new ArrayList(); 221 | Timber.plant(new Timber.DebugTree() { 222 | @Override protected void log(int priority, String tag, String message, Throwable t) { 223 | logs.add(priority + " " + tag + " " + message); 224 | } 225 | }); 226 | 227 | Timber.v("Verbose"); 228 | Timber.tag("Custom").v("Verbose"); 229 | Timber.d("Debug"); 230 | Timber.tag("Custom").d("Debug"); 231 | Timber.i("Info"); 232 | Timber.tag("Custom").i("Info"); 233 | Timber.w("Warn"); 234 | Timber.tag("Custom").w("Warn"); 235 | Timber.e("Error"); 236 | Timber.tag("Custom").e("Error"); 237 | Timber.wtf("Assert"); 238 | Timber.tag("Custom").wtf("Assert"); 239 | 240 | assertThat(logs).containsExactly( // 241 | "2 TimberTest Verbose", // 242 | "2 Custom Verbose", // 243 | "3 TimberTest Debug", // 244 | "3 Custom Debug", // 245 | "4 TimberTest Info", // 246 | "4 Custom Info", // 247 | "5 TimberTest Warn", // 248 | "5 Custom Warn", // 249 | "6 TimberTest Error", // 250 | "6 Custom Error", // 251 | "7 TimberTest Assert", // 252 | "7 Custom Assert" // 253 | ); 254 | } 255 | 256 | @Test public void logAtSpecifiedPriority() { 257 | Timber.plant(new Timber.DebugTree()); 258 | 259 | Timber.log(Log.VERBOSE, "Hello, World!"); 260 | Timber.log(Log.DEBUG, "Hello, World!"); 261 | Timber.log(Log.INFO, "Hello, World!"); 262 | Timber.log(Log.WARN, "Hello, World!"); 263 | Timber.log(Log.ERROR, "Hello, World!"); 264 | Timber.log(Log.ASSERT, "Hello, World!"); 265 | 266 | assertLog() 267 | .hasVerboseMessage("TimberTest", "Hello, World!") 268 | .hasDebugMessage("TimberTest", "Hello, World!") 269 | .hasInfoMessage("TimberTest", "Hello, World!") 270 | .hasWarnMessage("TimberTest", "Hello, World!") 271 | .hasErrorMessage("TimberTest", "Hello, World!") 272 | .hasAssertMessage("TimberTest", "Hello, World!") 273 | .hasNoMoreMessages(); 274 | } 275 | 276 | @Test public void formatting() { 277 | Timber.plant(new Timber.DebugTree()); 278 | Timber.v("Hello, %s!", "World"); 279 | Timber.d("Hello, %s!", "World"); 280 | Timber.i("Hello, %s!", "World"); 281 | Timber.w("Hello, %s!", "World"); 282 | Timber.e("Hello, %s!", "World"); 283 | Timber.wtf("Hello, %s!", "World"); 284 | 285 | assertLog() 286 | .hasVerboseMessage("TimberTest", "Hello, World!") 287 | .hasDebugMessage("TimberTest", "Hello, World!") 288 | .hasInfoMessage("TimberTest", "Hello, World!") 289 | .hasWarnMessage("TimberTest", "Hello, World!") 290 | .hasErrorMessage("TimberTest", "Hello, World!") 291 | .hasAssertMessage("TimberTest", "Hello, World!") 292 | .hasNoMoreMessages(); 293 | } 294 | 295 | @Test public void isLoggableControlsLogging() { 296 | Timber.plant(new Timber.DebugTree() { 297 | @Override protected boolean isLoggable(int priority) { 298 | return priority == Log.INFO; 299 | } 300 | }); 301 | Timber.v("Hello, World!"); 302 | Timber.d("Hello, World!"); 303 | Timber.i("Hello, World!"); 304 | Timber.w("Hello, World!"); 305 | Timber.e("Hello, World!"); 306 | Timber.wtf("Hello, World!"); 307 | 308 | assertLog() 309 | .hasInfoMessage("TimberTest", "Hello, World!") 310 | .hasNoMoreMessages(); 311 | } 312 | 313 | @Test public void logsUnknownHostExceptions() { 314 | Timber.plant(new Timber.DebugTree()); 315 | Timber.e(new UnknownHostException(), null); 316 | 317 | assertExceptionLogged("", "UnknownHostException"); 318 | } 319 | 320 | private static String repeat(char c, int number) { 321 | char[] data = new char[number]; 322 | Arrays.fill(data, c); 323 | return new String(data); 324 | } 325 | 326 | private static void assertExceptionLogged(String message, String exceptionClassname) { 327 | List logs = ShadowLog.getLogs(); 328 | assertThat(logs).hasSize(1); 329 | LogItem log = logs.get(0); 330 | assertThat(log.type).isEqualTo(Log.ERROR); 331 | assertThat(log.tag).isEqualTo("TimberTest"); 332 | assertThat(log.msg).startsWith(message); 333 | assertThat(log.msg).contains(exceptionClassname); 334 | // We use a low-level primitive that Robolectric doesn't populate. 335 | assertThat(log.throwable).isNull(); 336 | } 337 | 338 | private static LogAssert assertLog() { 339 | return new LogAssert(ShadowLog.getLogs()); 340 | } 341 | 342 | private static final class LogAssert { 343 | private final List items; 344 | private int index = 0; 345 | 346 | private LogAssert(List items) { 347 | this.items = items; 348 | } 349 | 350 | public LogAssert hasVerboseMessage(String tag, String message) { 351 | return hasMessage(Log.VERBOSE, tag, message); 352 | } 353 | 354 | public LogAssert hasDebugMessage(String tag, String message) { 355 | return hasMessage(Log.DEBUG, tag, message); 356 | } 357 | 358 | public LogAssert hasInfoMessage(String tag, String message) { 359 | return hasMessage(Log.INFO, tag, message); 360 | } 361 | 362 | public LogAssert hasWarnMessage(String tag, String message) { 363 | return hasMessage(Log.WARN, tag, message); 364 | } 365 | 366 | public LogAssert hasErrorMessage(String tag, String message) { 367 | return hasMessage(Log.ERROR, tag, message); 368 | } 369 | 370 | public LogAssert hasAssertMessage(String tag, String message) { 371 | return hasMessage(Log.ASSERT, tag, message); 372 | } 373 | 374 | private LogAssert hasMessage(int priority, String tag, String message) { 375 | LogItem item = items.get(index++); 376 | assertThat(item.type).isEqualTo(priority); 377 | assertThat(item.tag).isEqualTo(tag); 378 | assertThat(item.msg).isEqualTo(message); 379 | return this; 380 | } 381 | 382 | public void hasNoMoreMessages() { 383 | assertThat(items).hasSize(index); 384 | } 385 | } 386 | } 387 | -------------------------------------------------------------------------------- /xml/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /xml/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'checkstyle' 3 | 4 | task checkstyle(type: Checkstyle) { 5 | configFile rootProject.file('checkstyle.xml') 6 | source 'src/main/java' 7 | ignoreFailures false 8 | showViolations true 9 | include '**/*.java' 10 | 11 | classpath = files() 12 | } 13 | 14 | afterEvaluate { 15 | if (project.tasks.findByName('check')) { 16 | check.dependsOn('checkstyle') 17 | } 18 | } 19 | 20 | android { 21 | compileSdkVersion rootProject.ext.compileSdkVersion 22 | buildToolsVersion rootProject.ext.buildToolsVersion 23 | 24 | defaultConfig { 25 | minSdkVersion rootProject.ext.minSdkVersion 26 | targetSdkVersion rootProject.ext.targetSdkVersion 27 | consumerProguardFiles 'proguard-rules.pro' 28 | } 29 | } 30 | 31 | dependencies { 32 | testCompile deps.junit 33 | } 34 | 35 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') -------------------------------------------------------------------------------- /xml/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=xml 2 | POM_NAME=XML 3 | POM_PACKAGING=aar 4 | 5 | #VERSION_NAME=1.0.1-SNAPSHOT -------------------------------------------------------------------------------- /xml/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -keepattributes *Annotation*,*Exceptions*,Signature -------------------------------------------------------------------------------- /xml/src/androidTest/java/com/hwangjr/utils/xml/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.xml; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /xml/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /xml/src/main/java/com/hwangjr/utils/xml/XMLNode.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.xml; 2 | 3 | import java.util.HashMap; 4 | import java.util.LinkedList; 5 | 6 | public class XMLNode { 7 | 8 | public int mId; 9 | public String mName; 10 | public int mLevel; 11 | public long mFatherId; 12 | public LinkedList mChildrenList; 13 | public HashMap mAttributesMap; 14 | public String mText; 15 | 16 | public void addAttribute(String key, String value) { 17 | if (mAttributesMap == null) { 18 | mAttributesMap = new HashMap<>(); 19 | } 20 | mAttributesMap.put(key, value); 21 | } 22 | 23 | public String getAttributeValue(String attributeName) { 24 | if (mAttributesMap == null) { 25 | return null; 26 | } 27 | return mAttributesMap.get(attributeName); 28 | } 29 | 30 | public void addChild(XMLNode node) { 31 | if (mChildrenList == null) { 32 | mChildrenList = new LinkedList<>(); 33 | } 34 | mChildrenList.add(node); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /xml/src/main/java/com/hwangjr/utils/xml/XMLResolver.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.xml; 2 | 3 | import android.content.Context; 4 | import android.util.Xml; 5 | 6 | import org.xmlpull.v1.XmlPullParser; 7 | import org.xmlpull.v1.XmlPullParserException; 8 | 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.util.ArrayList; 12 | import java.util.LinkedList; 13 | import java.util.List; 14 | 15 | public class XMLResolver { 16 | 17 | public List readXml(XmlPullParser parser) { 18 | if (parser == null) { 19 | return null; 20 | } 21 | 22 | LinkedList nodeList = new LinkedList<>(); 23 | try { 24 | int eventType = parser.getEventType(); 25 | XMLNode node = null; 26 | 27 | while (eventType != XmlPullParser.END_DOCUMENT) { 28 | switch (eventType) { 29 | case XmlPullParser.START_TAG: 30 | node = initNode(parser); 31 | nodeList.add(node); 32 | break; 33 | case XmlPullParser.END_TAG: 34 | node = getLastNode(nodeList, parser.getName()); 35 | if (node != null) { 36 | if (node.mLevel > 1 && nodeList.size() > 0) { 37 | XMLNode father = getFatherNode(nodeList, node); 38 | node.mFatherId = father.mId; 39 | father.addChild(node); 40 | } 41 | } 42 | break; 43 | case XmlPullParser.TEXT: 44 | node = getLastNode(nodeList, parser.getDepth()); 45 | if (node != null) { 46 | if (parser.getText() != null && parser.getText().trim().length() > 0) { 47 | node.mText = parser.getText().trim(); 48 | } 49 | } 50 | break; 51 | default: 52 | break; 53 | } 54 | eventType = parser.next(); 55 | } 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } catch (XmlPullParserException e) { 59 | e.printStackTrace(); 60 | } 61 | return nodeList; 62 | } 63 | 64 | public List readXml(InputStream inputStream) { 65 | if (inputStream == null) { 66 | return null; 67 | } 68 | 69 | XmlPullParser parser = Xml.newPullParser(); 70 | try { 71 | parser.setInput(inputStream, "utf-8"); 72 | } catch (XmlPullParserException e) { 73 | e.printStackTrace(); 74 | } 75 | return readXml(parser); 76 | } 77 | 78 | /** 79 | * Read the xml file under assets folder. 80 | * 81 | * @param context context 82 | * @param fileName file name 83 | * @return 84 | */ 85 | public List readXml(Context context, String fileName) { 86 | InputStream inputStream = null; 87 | try { 88 | inputStream = context.getResources().getAssets().open(fileName); 89 | } catch (IOException e) { 90 | e.printStackTrace(); 91 | } 92 | List list = readXml(inputStream); 93 | try { 94 | inputStream.close(); 95 | } catch (IOException e) { 96 | e.printStackTrace(); 97 | } 98 | inputStream = null; 99 | return list; 100 | } 101 | 102 | /** 103 | * get xml node from node name. 104 | * 105 | * @param list 106 | * @param nodeName 107 | * @return 108 | */ 109 | public List getNode(List list, String nodeName) { 110 | List nodeList = new LinkedList(); 111 | for (XMLNode node : list) { 112 | if (node.mName.equals(nodeName)) { 113 | nodeList.add(node); 114 | } 115 | } 116 | return nodeList; 117 | } 118 | 119 | /** 120 | * get node attributes from node name and attribute name 121 | * 122 | * @param list 123 | * @param nodeName 124 | * @param attributeName 125 | * @return 126 | */ 127 | public List getAttributeValue(List list, String nodeName, String attributeName) { 128 | List valueList = new LinkedList(); 129 | for (XMLNode node : list) { 130 | if (node.mName.equals(nodeName)) { 131 | String value = node.getAttributeValue(attributeName); 132 | if (value != null) { 133 | valueList.add(value); 134 | } 135 | } 136 | } 137 | return valueList; 138 | } 139 | 140 | /** 141 | * get first attribute value from node name and attribute name 142 | * 143 | * @param list 144 | * @param nodeName 145 | * @param attributeName 146 | * @return 147 | */ 148 | public String getFirstAttributeValue(List list, String nodeName, String attributeName) { 149 | List valueList = getAttributeValue(list, nodeName, attributeName); 150 | if (valueList.size() > 0) { 151 | return valueList.get(0); 152 | } 153 | return null; 154 | } 155 | 156 | /** 157 | * get the child node from father node. 158 | * 159 | * @param source 160 | * @param fatherNode 161 | * @return 162 | */ 163 | public List getChildNodes(List source, String fatherNode) { 164 | if (source == null) { 165 | return null; 166 | } 167 | List list = new ArrayList(); 168 | for (XMLNode xmlNode : source) { 169 | if (xmlNode.mName.equals(fatherNode)) { 170 | list.add(xmlNode); 171 | } 172 | } 173 | return list; 174 | } 175 | 176 | public void print(List nodes) { 177 | for (XMLNode node : nodes) { 178 | StringBuilder builder = new StringBuilder(); 179 | builder.append("node name: " + node.mName + ", node text: " + node.mText + "\n"); 180 | if (node.mAttributesMap != null) { 181 | for (String key : node.mAttributesMap.keySet()) { 182 | String value = node.getAttributeValue(key); 183 | builder.append("attribute key: " + key + ", attribute value: " + value + "\n"); 184 | } 185 | } 186 | } 187 | } 188 | 189 | private XMLNode initNode(XmlPullParser parser) { 190 | XMLNode node = new XMLNode(); 191 | node.mId = node.hashCode(); 192 | node.mName = parser.getName(); 193 | node.mLevel = parser.getDepth(); 194 | for (int i = 0; i < parser.getAttributeCount(); i++) { 195 | node.addAttribute(parser.getAttributeName(i), parser.getAttributeValue(i)); 196 | } 197 | return node; 198 | } 199 | 200 | private XMLNode getLastNode(LinkedList nodeList, String name) { 201 | for (int i = nodeList.size() - 1; i >= 0; i--) { 202 | if (nodeList.get(i).mName.equals(name)) { 203 | return nodeList.get(i); 204 | } 205 | } 206 | return null; 207 | } 208 | 209 | private XMLNode getLastNode(LinkedList nodeList, int depth) { 210 | for (int i = nodeList.size() - 1; i >= 0; i--) { 211 | if (nodeList.get(i).mLevel == depth) { 212 | return nodeList.get(i); 213 | } 214 | } 215 | return null; 216 | } 217 | 218 | private XMLNode getFatherNode(LinkedList nodeList, XMLNode childNode) { 219 | for (int i = nodeList.size() - 1; i >= 0; i--) { 220 | if (nodeList.get(i).mLevel == childNode.mLevel - 1) { 221 | return nodeList.get(i); 222 | } 223 | } 224 | return null; 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /xml/src/test/java/com/hwangjr/utils/xml/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hwangjr.utils.xml; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } --------------------------------------------------------------------------------