parent
							
								
									d8a14c0086
								
							
						
					
					
						commit
						0f9f2577b8
					
				| @ -0,0 +1,4 @@ | ||||
| /build | ||||
| mvvm2.iml | ||||
| #jcenter.gradle | ||||
| gradle.properties | ||||
| @ -0,0 +1,201 @@ | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
| 
 | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
| 
 | ||||
|    1. Definitions. | ||||
| 
 | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
| 
 | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
| 
 | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
| 
 | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
| 
 | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
| 
 | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
| 
 | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
| 
 | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
| 
 | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
| 
 | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
| 
 | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
| 
 | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
| 
 | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
| 
 | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
| 
 | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
| 
 | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
| 
 | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
| 
 | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
| 
 | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
| 
 | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
| 
 | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
| 
 | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
| 
 | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
| 
 | ||||
|    END OF TERMS AND CONDITIONS | ||||
| 
 | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
| 
 | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "{}" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
| 
 | ||||
|    Copyright {yyyy} {name of copyright owner} | ||||
| 
 | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
| 
 | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| @ -0,0 +1,39 @@ | ||||
| apply plugin: 'com.android.library' | ||||
| //apply plugin: 'com.neenbedankt.android-apt' | ||||
| android { | ||||
|   compileSdkVersion rootProject.ext.compileSdkVersion | ||||
|   buildToolsVersion rootProject.ext.buildToolsVersion | ||||
| 
 | ||||
|   defaultConfig { | ||||
|     minSdkVersion rootProject.ext.minSdkVersion | ||||
|     targetSdkVersion rootProject.ext.targetSdkVersion | ||||
|     versionCode 61 | ||||
|     versionName "1.0" | ||||
|   } | ||||
|   buildTypes { | ||||
|     release { | ||||
|       minifyEnabled false | ||||
|       proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|     } | ||||
|   } | ||||
|   dataBinding { | ||||
|     enabled = true | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| dependencies { | ||||
|   implementation fileTree(include: ['*.jar'], dir: 'libs') | ||||
|   testImplementation 'junit:junit:4.12' | ||||
|   implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}" | ||||
|   implementation 'com.google.code.gson:gson:2.7' | ||||
|   //    compile 'com.squareup.retrofit2:retrofit:2.1.0' | ||||
|   //    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' | ||||
|   //    compile 'com.squareup.retrofit2:converter-gson:2.1.0' | ||||
|   implementation 'com.squareup.okhttp3:okhttp:3.2.0' | ||||
|   //    compile 'com.squareup.okhttp3:logging-interceptor:3.2.0' | ||||
|   //    compile 'com.google.dagger:dagger:2.5' | ||||
|   //    apt 'com.google.dagger:dagger-compiler:2.5' | ||||
|   //    provided 'javax.annotation:jsr250-api:1.0' | ||||
| } | ||||
| 
 | ||||
| //apply from: 'jcenter.gradle' | ||||
| @ -0,0 +1,168 @@ | ||||
| group = PROJ_GROUP | ||||
| version = PROJ_VERSION | ||||
| project.archivesBaseName = PROJ_ARTIFACTID | ||||
| apply plugin: 'com.jfrog.bintray' | ||||
| apply plugin: "com.jfrog.artifactory" | ||||
| apply plugin: 'maven-publish' | ||||
| 
 | ||||
| task sourcesJar(type: Jar) { | ||||
|   from android.sourceSets.main.java.srcDirs | ||||
|   classifier = 'sources' | ||||
| } | ||||
| 
 | ||||
| task javadoc(type: Javadoc) { | ||||
|   source = android.sourceSets.main.java.srcDirs | ||||
|   classpath += configurations.compile | ||||
|   classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) | ||||
| } | ||||
| 
 | ||||
| task javadocJar(type: Jar, dependsOn: javadoc) { | ||||
|   classifier = 'javadoc' | ||||
|   from javadoc.destinationDir | ||||
| } | ||||
| 
 | ||||
| javadoc { | ||||
|   options { | ||||
|     encoding "UTF-8" | ||||
|     charSet 'UTF-8' | ||||
|     author true | ||||
|     version true | ||||
|     links "http://docs.oracle.com/javase/7/docs/api" | ||||
|     title PROJ_ARTIFACTID | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| //添加以下信息避免JAVADOC打包时引用其它类库而出现问题,比如出现以下错误 | ||||
| // xxxx.java:20: 错误: 找不到符号 | ||||
| // public static <T> T create(JsonElement json, Class<T> classOfModel) { | ||||
| //    ^ | ||||
| //    符号:   类 JsonElement | ||||
| //    位置: 类 xxxx | ||||
| android.libraryVariants.all { variant -> | ||||
|   println variant.javaCompile.classpath.files | ||||
|   if (variant.name == 'release') { | ||||
|     //我们只需 release 的 javadoc | ||||
|     task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) { | ||||
|       // title = '' | ||||
|       // description = '' | ||||
|       source = variant.javaCompile.source | ||||
|       classpath = files(variant.javaCompile.classpath.files, project.android.getBootClasspath()) | ||||
|       options { | ||||
|         encoding "utf-8" | ||||
|         links "http://docs.oracle.com/javase/7/docs/api/" | ||||
|         linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference" | ||||
|       } | ||||
|       exclude '**/BuildConfig.java' | ||||
|       exclude '**/R.java' | ||||
|     } | ||||
|     task("javadoc${variant.name.capitalize()}Jar", type: Jar, | ||||
|         dependsOn: "generate${variant.name.capitalize()}Javadoc") { | ||||
|       classifier = 'javadoc' | ||||
|       from tasks.getByName("generate${variant.name.capitalize()}Javadoc").destinationDir | ||||
|     } | ||||
|     artifacts { | ||||
|       archives tasks.getByName("javadoc${variant.name.capitalize()}Jar") | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| artifacts { | ||||
|   archives javadocJar | ||||
|   archives sourcesJar | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| def pomConfig = { | ||||
|   scm { | ||||
|     connection PROJ_VCSURL | ||||
|     developerConnection PROJ_VCSURL | ||||
|     url PROJ_WEBSITEURL | ||||
|   } | ||||
|   licenses { | ||||
|     license { | ||||
|       name "The Apache Software License, Version 2.0" | ||||
|       url "http://www.apache.org/licenses/LICENSE-2.0.txt" | ||||
|       distribution "repo" | ||||
|     } | ||||
|   } | ||||
|   developers { | ||||
|     developer { | ||||
|       id DEVELOPER_ID | ||||
|       name DEVELOPER_NAME | ||||
|       email DEVELOPER_EMAIL | ||||
|     } | ||||
|   } | ||||
|   "dependencies " { | ||||
|     //        dependency { | ||||
|     //            groupId "com.alibaba" | ||||
|     //            artifactId "fastjson" | ||||
|     //            "version " "1.2.6" | ||||
|     //            //同dependencies | ||||
|     //        } | ||||
|     //        } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| publishing { | ||||
|   publications { | ||||
|     mavenJava(MavenPublication) { | ||||
|       artifactId PROJ_ARTIFACTID | ||||
|       artifact javadocJar | ||||
|       artifact sourcesJar | ||||
| 
 | ||||
|       pom { | ||||
|         packaging 'aar' | ||||
|       } | ||||
|       pom.withXml { | ||||
|         def root = asNode() | ||||
|         root.appendNode('description', PROJ_DESCRIPTION) | ||||
|         root.children().last() + pomConfig | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| afterEvaluate { | ||||
|   publishing.publications.mavenJava.artifact(bundleRelease) | ||||
| } | ||||
| 
 | ||||
| bintray { | ||||
|   user = hasProperty("bintrayUser") ? getProperty("bintrayUser") : getProperty("BINTRAY_USER") | ||||
|   key = hasProperty("bintrayKey") ? getProperty("bintrayKey") : getProperty("BINTRAY_KEY") | ||||
| 
 | ||||
|   configurations = ['archives'] | ||||
|   publications = ['mavenJava'] | ||||
|   publish = true | ||||
| 
 | ||||
|   pkg { | ||||
|     repo = 'maven' | ||||
|     name = PROJ_NAME | ||||
|     desc = PROJ_DESCRIPTION | ||||
|     websiteUrl = PROJ_WEBSITEURL | ||||
|     issueTrackerUrl = PROJ_ISSUETRACKERURL | ||||
|     vcsUrl = PROJ_VCSURL | ||||
|     licenses = ['Apache-2.0'] | ||||
|     publicDownloadNumbers = true | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| artifactory { | ||||
|   contextUrl = 'http://oss.jfrog.org/artifactory' | ||||
|   resolve { | ||||
|     repository { | ||||
|       repoKey = 'libs-release' | ||||
|     } | ||||
|   } | ||||
|   publish { | ||||
|     repository { | ||||
|       repoKey = 'oss-snapshot-local' //The Artifactory repository key to publish to | ||||
|       username = bintray.user | ||||
|       password = bintray.key | ||||
|       maven = true | ||||
|     } | ||||
|     defaults { | ||||
|       publications('mavenJava') | ||||
|       publishArtifacts = true | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| # Add project specific ProGuard rules here. | ||||
| # By default, the flags in this file are appended to flags specified | ||||
| # in E:\sdk/tools/proguard/proguard-android.txt | ||||
| # You can edit the include path and order by changing the proguardFiles | ||||
| # directive in build.gradle. | ||||
| # | ||||
| # For more details, see | ||||
| #   http://developer.android.com/guide/developing/tools/proguard.html | ||||
| 
 | ||||
| # Add any project specific keep options here: | ||||
| 
 | ||||
| # If your project uses WebView with JS, uncomment the following | ||||
| # and specify the fully qualified class name to the JavaScript interface | ||||
| # class: | ||||
| #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||||
| #   public *; | ||||
| #} | ||||
| @ -0,0 +1,14 @@ | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="com.lyy.frame"> | ||||
| 
 | ||||
|   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> | ||||
|   <uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/> | ||||
| 
 | ||||
|   <application | ||||
|       android:allowBackup="true" | ||||
|       android:label="@string/app_name" | ||||
|       android:supportsRtl="true"> | ||||
| 
 | ||||
|   </application> | ||||
| 
 | ||||
| </manifest> | ||||
| @ -0,0 +1,367 @@ | ||||
| package com.arialyy.frame.cache; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.v4.util.LruCache; | ||||
| import android.text.TextUtils; | ||||
| import com.arialyy.frame.cache.diskcache.DiskLruCache; | ||||
| import com.arialyy.frame.util.AndroidUtils; | ||||
| import com.arialyy.frame.util.AppUtils; | ||||
| import com.arialyy.frame.util.StreamUtil; | ||||
| import com.arialyy.frame.util.StringUtil; | ||||
| import com.arialyy.frame.util.show.FL; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
| 
 | ||||
| /** | ||||
|  * Created by “AriaLyy@outlook.com” on 2015/4/9. | ||||
|  * 缓存抽象类,封装了缓存的读写操作 | ||||
|  */ | ||||
| abstract class AbsCache implements CacheParam { | ||||
|   private static final String TAG = "AbsCache"; | ||||
|   private static final Object LOCK = new Object(); | ||||
|   /** | ||||
|    * 磁盘缓存工具 | ||||
|    */ | ||||
|   private DiskLruCache mDiskLruCache = null; | ||||
|   /** | ||||
|    * 内存缓存工具 | ||||
|    */ | ||||
|   private LruCache<String, byte[]> mMemoryCache = null; | ||||
|   /** | ||||
|    * 是否使用内存缓存 | ||||
|    */ | ||||
|   private boolean useMemory = false; | ||||
|   /** | ||||
|    * 是否使用磁盘缓存 | ||||
|    */ | ||||
|   private boolean useDisk = false; | ||||
|   /** | ||||
|    * 最大的内存 | ||||
|    */ | ||||
|   private int mMaxMemoryCacheSize; | ||||
|   /** | ||||
|    * 最大的磁盘大小 | ||||
|    */ | ||||
|   private long mMaxDiskCacheSize; | ||||
|   private Context mContext; | ||||
| 
 | ||||
|   /** | ||||
|    * 默认使用默认路径 | ||||
|    */ | ||||
|   protected AbsCache(Context context) { | ||||
|     this(context, DEFAULT_DIR); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 指定缓存文件夹 | ||||
|    * | ||||
|    * @param cacheDir 缓存文件夹 | ||||
|    */ | ||||
|   AbsCache(Context context, @NonNull String cacheDir) { | ||||
|     this.mContext = context; | ||||
|     init(cacheDir, 1, SMALL_DISK_CACHE_CAPACITY); | ||||
|   } | ||||
| 
 | ||||
|   private void init(String cacheDir, int valueCount, long cacheSize) { | ||||
|     initDiskCache(cacheDir, valueCount, cacheSize); | ||||
|     initMemoryCache(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 初始化磁盘缓存 | ||||
|    */ | ||||
|   private void initDiskCache(String cacheDir, int valueCount, long cacheSize) { | ||||
|     try { | ||||
|       File dir = getDiskCacheDir(mContext, cacheDir); | ||||
|       if (!dir.exists()) { | ||||
|         dir.mkdirs(); | ||||
|       } | ||||
|       mDiskLruCache = | ||||
|           DiskLruCache.open(dir, AppUtils.getVersionNumber(mContext), valueCount, cacheSize); | ||||
|     } catch (IOException e) { | ||||
|       FL.e(this, "createCacheFailed\n" + FL.getExceptionString(e)); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 初始化内存缓存 | ||||
|    */ | ||||
|   private void initMemoryCache() { | ||||
|     if (!useMemory) return; | ||||
|     // 获取应用程序最大可用内存
 | ||||
|     mMaxMemoryCacheSize = (int) Runtime.getRuntime().maxMemory(); | ||||
|     // 设置图片缓存大小为程序最大可用内存的1/8
 | ||||
|     mMemoryCache = new LruCache<>(mMaxMemoryCacheSize / 8); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 是否使用内存缓存 | ||||
|    */ | ||||
|   void setUseMemory(boolean useMemory) { | ||||
|     this.useMemory = useMemory; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 是否使用磁盘缓存 | ||||
|    */ | ||||
|   void setUseDisk(boolean useDisk) { | ||||
|     this.useDisk = useDisk; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置内存缓存大小 | ||||
|    */ | ||||
|   void setMemoryCacheSize(int size) { | ||||
|     if (useMemory && mMemoryCache != null) { | ||||
|       mMemoryCache.resize(size); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 打开某个目录下的缓存 | ||||
|    * | ||||
|    * @param cacheDir 缓存目录,只需填写文件夹名,不需要写路径 | ||||
|    * @param valueCount 指定同一个key可以对应多少个缓存文件,基本都是传1 | ||||
|    * @param cacheSize 缓存大小 | ||||
|    * @see CacheParam | ||||
|    */ | ||||
|   void openDiskCache(@NonNull String cacheDir, int valueCount, long cacheSize) { | ||||
|     synchronized (LOCK) { | ||||
|       if (mDiskLruCache != null && mDiskLruCache.isClosed()) { | ||||
|         try { | ||||
|           File dir = getDiskCacheDir(mContext, cacheDir); | ||||
|           if (!dir.exists()) { | ||||
|             dir.mkdirs(); | ||||
|           } | ||||
|           mDiskLruCache = | ||||
|               DiskLruCache.open(dir, AppUtils.getVersionNumber(mContext), valueCount, cacheSize); | ||||
|         } catch (IOException e) { | ||||
|           FL.e(this, "createCacheFailed\n" + FL.getExceptionString(e)); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 把缓存写入磁盘 | ||||
|    * | ||||
|    * @param key 缓存的key,通过该key来读写缓存,一般是URL | ||||
|    * @param data 缓存的数据 | ||||
|    */ | ||||
|   void writeDiskCache(@NonNull String key, @NonNull byte[] data) { | ||||
|     if (TextUtils.isEmpty(key)) { | ||||
|       L.e(TAG, "key 不能为null"); | ||||
|       return; | ||||
|     } | ||||
|     String hashKey = StringUtil.keyToHashKey(key); | ||||
|     if (useMemory && mMemoryCache != null) { | ||||
|       mMemoryCache.put(hashKey, data); | ||||
|     } | ||||
|     if (useDisk) { | ||||
|       synchronized (LOCK) { | ||||
|         if (mDiskLruCache != null) { | ||||
|           L.i(TAG, "缓存数据到磁盘[key:" + key + ",hashKey:" + hashKey + "]"); | ||||
|           OutputStream out = null; | ||||
|           try { | ||||
|             DiskLruCache.Editor editor = mDiskLruCache.edit(hashKey); | ||||
|             out = editor.newOutputStream(DISK_CACHE_INDEX); | ||||
|             out.write(data, 0, data.length); | ||||
|             editor.commit(); | ||||
|             out.flush(); | ||||
|             out.close(); | ||||
|           } catch (IOException e) { | ||||
|             FL.e(this, "writeDiskFailed[key:" | ||||
|                 + key | ||||
|                 + ",hashKey:" | ||||
|                 + hashKey | ||||
|                 + "]\n" | ||||
|                 + FL.getExceptionString(e)); | ||||
|           } finally { | ||||
|             if (out != null) { | ||||
|               try { | ||||
|                 out.close(); | ||||
|               } catch (IOException e) { | ||||
|                 e.printStackTrace(); | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从磁盘读取缓存 | ||||
|    * | ||||
|    * @param key 缓存的key,一般是原来的url | ||||
|    * @return 缓存数据 | ||||
|    */ | ||||
|   byte[] readDiskCache(@NonNull String key) { | ||||
|     if (TextUtils.isEmpty(key)) { | ||||
|       return null; | ||||
|     } | ||||
|     String hashKey = StringUtil.keyToHashKey(key); | ||||
|     if (useMemory && mMemoryCache != null) { | ||||
|       final byte[] data = mMemoryCache.get(hashKey); | ||||
|       if (data != null && data.length != 0) { | ||||
|         return data; | ||||
|       } | ||||
|     } | ||||
|     if (useDisk) { | ||||
|       synchronized (LOCK) { | ||||
|         byte[] data = null; | ||||
|         L.i(TAG, "读取磁盘缓存数据[key:" + key + ",hashKey:" + hashKey + "]"); | ||||
|         InputStream inputStream = null; | ||||
|         try { | ||||
|           DiskLruCache.Snapshot snapshot = mDiskLruCache.get(hashKey); | ||||
|           if (snapshot != null) { | ||||
|             inputStream = snapshot.getInputStream(DISK_CACHE_INDEX); | ||||
|             data = StreamUtil.readStream(inputStream); | ||||
|             return data; | ||||
|           } | ||||
|         } catch (Exception e) { | ||||
|           FL.e(this, "readDiskCacheFailed[key:" | ||||
|               + key | ||||
|               + ",hashKey:" | ||||
|               + hashKey | ||||
|               + "]\n" | ||||
|               + FL.getExceptionString(e)); | ||||
|         } finally { | ||||
|           if (inputStream != null) { | ||||
|             try { | ||||
|               inputStream.close(); | ||||
|             } catch (IOException e) { | ||||
|               e.printStackTrace(); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 删除一条缓存 | ||||
|    * | ||||
|    * @param key 该缓存的key | ||||
|    */ | ||||
|   protected void removeCache(@NonNull String key) { | ||||
|     String hashKey = StringUtil.keyToHashKey(key); | ||||
|     if (mMemoryCache != null) { | ||||
|       mMemoryCache.remove(hashKey); | ||||
|     } | ||||
|     synchronized (LOCK) { | ||||
|       if (mDiskLruCache != null) { | ||||
|         try { | ||||
|           mDiskLruCache.remove(hashKey); | ||||
|         } catch (IOException e) { | ||||
|           FL.e(this, "removeCacheFailed[key:" | ||||
|               + key | ||||
|               + ",hashKey:" | ||||
|               + hashKey | ||||
|               + "]\n" | ||||
|               + FL.getExceptionString(e)); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 关闭内存缓存 | ||||
|    */ | ||||
|   void closeMemoryCache() { | ||||
|     if (mMemoryCache != null) { | ||||
|       mMemoryCache.evictAll(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 清除所有缓存 | ||||
|    */ | ||||
|   void clearCache() { | ||||
|     if (mMemoryCache != null) { | ||||
|       mMemoryCache.evictAll(); | ||||
|     } | ||||
|     synchronized (LOCK) { | ||||
|       if (mDiskLruCache != null) { | ||||
|         try { | ||||
|           mDiskLruCache.delete(); | ||||
|         } catch (IOException e) { | ||||
|           FL.e(this, "clearCacheFailed" + FL.getExceptionString(e)); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 关闭磁盘缓存,注意: | ||||
|    * 这个方法用于将DiskLruCache关闭掉,是和open()方法对应的一个方法。 | ||||
|    * 关闭掉了之后就不能再调用DiskLruCache中任何操作缓存数据的方法, | ||||
|    * 通常只应该在Activity的onDestroy()方法中去调用close()方法。 | ||||
|    */ | ||||
|   void closeDiskCache() { | ||||
|     synchronized (LOCK) { | ||||
|       if (mDiskLruCache != null) { | ||||
|         try { | ||||
|           mDiskLruCache.close(); | ||||
|         } catch (IOException e) { | ||||
|           FL.e(this, "closeDiskCacheFailed" + FL.getExceptionString(e)); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 同步内存中的缓存操作记录到日志文件(也就是journal文件) | ||||
|    * 注意:在写入缓存时需要flush同步一次,并不是每次写入缓存都要调用一次flush()方法的,频繁地调用并不会带来任何好处, | ||||
|    * 只会额外增加同步journal文件的时间。比较标准的做法就是在Activity的onPause()方法中去调用一次flush()方法就可以了 | ||||
|    */ | ||||
|   void flushDiskCache() { | ||||
|     synchronized (LOCK) { | ||||
|       if (mDiskLruCache != null) { | ||||
|         try { | ||||
|           mDiskLruCache.flush(); | ||||
|         } catch (IOException e) { | ||||
|           FL.e(this, "flushDiskCacheFailed" + FL.getExceptionString(e)); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取缓存大小 | ||||
|    */ | ||||
|   protected long getCacheSize() { | ||||
|     return mDiskLruCache.size(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 生成缓存文件夹 | ||||
|    * | ||||
|    * @param uniqueName 缓存文件夹名 | ||||
|    * @return 缓存文件夹 | ||||
|    */ | ||||
|   public static File getDiskCacheDir(Context context, String uniqueName) { | ||||
|     return new File(AndroidUtils.getDiskCacheDir(context) + File.separator + uniqueName); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 转换byte数组为String | ||||
|    */ | ||||
|   private static String bytesToHexString(byte[] bytes) { | ||||
|     // http://stackoverflow.com/questions/332079
 | ||||
|     StringBuilder sb = new StringBuilder(); | ||||
|     for (byte aByte : bytes) { | ||||
|       String hex = Integer.toHexString(0xFF & aByte); | ||||
|       if (hex.length() == 1) { | ||||
|         sb.append('0'); | ||||
|       } | ||||
|       sb.append(hex); | ||||
|     } | ||||
|     return sb.toString(); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,81 @@ | ||||
| package com.arialyy.frame.cache; | ||||
| 
 | ||||
| import android.text.TextUtils; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| 
 | ||||
| /** | ||||
|  * Created by “AriaLyy@outlook.com” on 2015/4/9. | ||||
|  */ | ||||
| public class CacheHelp { | ||||
| 
 | ||||
|   /** | ||||
|    * 设置缓存有效时间 | ||||
|    */ | ||||
|   public static void setCacheAvailableTime(long availableTime) { | ||||
|     CacheObj.CACHE_INTERVAL = availableTime; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 储存缓存 | ||||
|    */ | ||||
|   public static void saveCache(CacheUtil util, String key, String value) { | ||||
|     if (TextUtils.isEmpty(value)) { | ||||
|       L.e("缓存数据位null"); | ||||
|       return; | ||||
|     } | ||||
|     CacheObj cache = util.getObjectCache(CacheObj.class, key); | ||||
|     if (cache == null) { | ||||
|       cache = new CacheObj(); | ||||
|     } | ||||
|     cache.setCacheTime(System.currentTimeMillis()); | ||||
|     cache.setAvailableNum(cache.getAvailableNum() + 1); | ||||
|     cache.setData(value); | ||||
|     util.putObjectCache(CacheObj.class, key, cache); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取有效的缓存 | ||||
|    */ | ||||
|   public static CacheObj getAvailableCache(CacheUtil util, String url, Map<String, String> param) { | ||||
|     if (TextUtils.isEmpty(url)) { | ||||
|       return null; | ||||
|     } | ||||
|     String key = getKey(url, param); | ||||
|     CacheObj cache = util.getObjectCache(CacheObj.class, key); | ||||
|     if (cache == null) { | ||||
|       return null; | ||||
|     } | ||||
|     if (cache.isAvailable()) { | ||||
|       return cache; | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取缓存,有效或无效 | ||||
|    */ | ||||
|   public static CacheObj getCache(CacheUtil util, String url, Map<String, String> param) { | ||||
|     if (TextUtils.isEmpty(url)) { | ||||
|       return null; | ||||
|     } | ||||
|     String key = getKey(url, param); | ||||
|     return util.getObjectCache(CacheObj.class, key); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 通过url和请求参数获取key | ||||
|    */ | ||||
|   public static String getKey(String url, Map<String, String> param) { | ||||
|     if (param == null || param.size() == 0) { | ||||
|       return url; | ||||
|     } | ||||
|     String p = ""; | ||||
|     for (Map.Entry<String, String> entry : param.entrySet()) { | ||||
|       p += "[" + entry.getKey() + "," + entry.getValue() + "];"; | ||||
|     } | ||||
|     url += ";" + p; | ||||
|     return url; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,56 @@ | ||||
| package com.arialyy.frame.cache; | ||||
| 
 | ||||
| /** | ||||
|  * Created by “AriaLyy@outlook.com” on 2015/4/9. | ||||
|  * 缓存对象 | ||||
|  */ | ||||
| class CacheObj { | ||||
|   /** | ||||
|    * 缓存有效请求时间 | ||||
|    */ | ||||
|   public static long CACHE_INTERVAL = 120 * 1000; | ||||
|   /** | ||||
|    * 缓存有效请求次数 | ||||
|    */ | ||||
|   public static final int CACHE_NUM_INTERVAL = 5; | ||||
|   private long cacheTime = 0; | ||||
|   private long availableNum = 0; | ||||
| 
 | ||||
|   private String data; | ||||
| 
 | ||||
|   /** | ||||
|    * 缓存是否有效 | ||||
|    */ | ||||
|   public boolean isAvailable() { | ||||
|     if (System.currentTimeMillis() - cacheTime > CACHE_INTERVAL) { | ||||
|       return false; | ||||
|     } else if (availableNum >= CACHE_NUM_INTERVAL) { | ||||
|       return false; | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   public String getData() { | ||||
|     return data; | ||||
|   } | ||||
| 
 | ||||
|   public void setData(String data) { | ||||
|     this.data = data; | ||||
|   } | ||||
| 
 | ||||
|   public long getCacheTime() { | ||||
|     return cacheTime; | ||||
|   } | ||||
| 
 | ||||
|   public void setCacheTime(long cacheTime) { | ||||
|     this.cacheTime = cacheTime; | ||||
|   } | ||||
| 
 | ||||
|   public long getAvailableNum() { | ||||
|     return availableNum; | ||||
|   } | ||||
| 
 | ||||
|   public void setAvailableNum(long availableNum) { | ||||
|     this.availableNum = availableNum; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,37 @@ | ||||
| package com.arialyy.frame.cache; | ||||
| 
 | ||||
| /** | ||||
|  * Created by “AriaLyy@outlook.com” on 2015/4/9. | ||||
|  * 缓存参数 | ||||
|  */ | ||||
| interface CacheParam { | ||||
| 
 | ||||
|   /** | ||||
|    * 磁盘缓存 | ||||
|    */ | ||||
|   public static final int DISK_CACHE = 0; | ||||
|   /** | ||||
|    * 默认缓存目录文件夹名 | ||||
|    */ | ||||
|   public static final String DEFAULT_DIR = "defaultDir"; | ||||
|   /** | ||||
|    * 内存缓存 | ||||
|    */ | ||||
|   public static final int MEMORY_CACHE_SIZE = 4 * 1024 * 1024; | ||||
|   /** | ||||
|    * 小容量磁盘缓存 | ||||
|    */ | ||||
|   public static final long SMALL_DISK_CACHE_CAPACITY = 4 * 1024 * 1024; | ||||
|   /** | ||||
|    * 中型容量磁盘缓存 | ||||
|    */ | ||||
|   public static final long NORMAL_DISK_CACHE_CAPACITY = 10 * 1024 * 1024; | ||||
|   /** | ||||
|    * 大容量磁盘缓存 | ||||
|    */ | ||||
|   public static final long LARGER_DISKCACHE_CAPACITY = 20 * 1024 * 1024; | ||||
|   /** | ||||
|    * 缓存index | ||||
|    */ | ||||
|   public static final int DISK_CACHE_INDEX = 0; | ||||
| } | ||||
| @ -0,0 +1,262 @@ | ||||
| package com.arialyy.frame.cache; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.graphics.Bitmap; | ||||
| import android.support.annotation.NonNull; | ||||
| import com.arialyy.frame.util.DrawableUtil; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| import com.google.gson.Gson; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| 
 | ||||
| /** | ||||
|  * Created by “AriaLyy@outlook.com” on 2015/4/9. | ||||
|  * 缓存工具 | ||||
|  */ | ||||
| public class CacheUtil extends AbsCache { | ||||
|   private static final String TAG = "CacheUtil"; | ||||
| 
 | ||||
|   /** | ||||
|    * 默认使用默认路径 | ||||
|    */ | ||||
|   private CacheUtil(Context context) { | ||||
|     this(context, DEFAULT_DIR); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 指定缓存文件夹 | ||||
|    * | ||||
|    * @param cacheDir 缓存文件夹名 | ||||
|    */ | ||||
|   private CacheUtil(Context context, @NonNull String cacheDir) { | ||||
|     super(context, cacheDir); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 是否使用内存缓存 | ||||
|    */ | ||||
|   private void setUseMemoryCache(boolean openMemoryCache) { | ||||
|     setUseMemory(openMemoryCache); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 是否使用磁场缓存 | ||||
|    */ | ||||
|   private void setUseDiskCache(boolean openDiskCache) { | ||||
|     setUseMemory(openDiskCache); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 打开某个目录下的缓存 | ||||
|    * | ||||
|    * @param cacheDir 缓存目录,只需填写文件夹名,不需要写路径 | ||||
|    * @param valueCount 指定同一个key可以对应多少个缓存文件,基本都是传1 | ||||
|    * @param cacheSize 缓存大小 | ||||
|    * @see CacheParam | ||||
|    */ | ||||
|   public void openCache(String cacheDir, int valueCount, long cacheSize) { | ||||
|     openDiskCache(cacheDir, valueCount, cacheSize); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 写入Bitmap类型缓存,注意:需要在特定的时候flush,一般在onPause()里面写,onDestroy() | ||||
|    * | ||||
|    * @param key 键值,一般是url | ||||
|    * @param bitmap 需要写入的数据 | ||||
|    */ | ||||
|   public void putBitmapCache(String key, Bitmap bitmap) { | ||||
|     byte[] data = DrawableUtil.getBitmapByte(bitmap); | ||||
|     putByteCache(key, data); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取缓存中的bitmap | ||||
|    */ | ||||
|   public Bitmap getBitmapCache(String key) { | ||||
|     byte[] data = getByteCache(key); | ||||
|     return DrawableUtil.getBitmapFromByte(data); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 写入String类型缓存,注意:需要在特定的时候flush,一般在onPause()里面写,onDestroy() | ||||
|    * | ||||
|    * @param key 键值,一般是url | ||||
|    * @param data 需要写入的数据 | ||||
|    */ | ||||
|   public void putStringCache(String key, String data) { | ||||
|     try { | ||||
|       putByteCache(key, data.getBytes("utf-8")); | ||||
|     } catch (UnsupportedEncodingException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 读取字符串缓存 | ||||
|    */ | ||||
|   public String getStringCache(String key) { | ||||
|     byte[] data = getByteCache(key); | ||||
|     String str = ""; | ||||
|     if (data != null) { | ||||
|       try { | ||||
|         str = new String(data, "utf-8"); | ||||
|       } catch (UnsupportedEncodingException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|     } | ||||
|     return str; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 写入byte类型缓存,注意:需要在特定的时候flush,一般在onPause()里面写,onDestroy() | ||||
|    * | ||||
|    * @param key 键值,一般是url | ||||
|    * @param data 需要写入的数据 | ||||
|    */ | ||||
|   public void putByteCache(String key, byte[] data) { | ||||
|     writeDiskCache(key, data); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 读取byte类型缓存 | ||||
|    * | ||||
|    * @param key 缓存的key | ||||
|    */ | ||||
|   public byte[] getByteCache(String key) { | ||||
|     return readDiskCache(key); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 写入对象缓存后,注意:需要在特定的时候flush,一般在onPause()里面写,onDestroy() | ||||
|    * | ||||
|    * @param clazz 对象类型 | ||||
|    * @param key 缓存键值 | ||||
|    * @param object 对象 | ||||
|    */ | ||||
|   public void putObjectCache(Class<?> clazz, String key, Object object) { | ||||
|     String json = new Gson().toJson(object, clazz); | ||||
|     try { | ||||
|       writeDiskCache(key, json.getBytes("utf-8")); | ||||
|     } catch (UnsupportedEncodingException e) { | ||||
|       L.e(TAG, "编码转换错误", e); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 读取对象缓存 | ||||
|    * | ||||
|    * @param clazz 对象类型 | ||||
|    * @param key 缓存键值 | ||||
|    */ | ||||
|   public <T> T getObjectCache(Class<T> clazz, String key) { | ||||
|     T object = null; | ||||
|     try { | ||||
|       byte[] data = readDiskCache(key); | ||||
|       if (data == null) { | ||||
|         return null; | ||||
|       } | ||||
|       object = new Gson().fromJson(new String(data, "utf-8"), clazz); | ||||
|     } catch (UnsupportedEncodingException e) { | ||||
|       L.e(TAG, "编码转换错误", e); | ||||
|     } | ||||
|     return object; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 同步记录,不同步则提取不了缓存 | ||||
|    */ | ||||
|   public void flush() { | ||||
|     flushDiskCache(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 删除一条缓存 | ||||
|    * | ||||
|    * @param key 缓存键值 | ||||
|    */ | ||||
|   public void remove(String key) { | ||||
|     readDiskCache(key); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 删除所有缓存 | ||||
|    */ | ||||
|   public void clearCache() { | ||||
|     super.clearCache(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 关闭磁盘缓存 | ||||
|    */ | ||||
|   public void close() { | ||||
|     closeMemoryCache(); | ||||
|     closeDiskCache(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取缓存大小 | ||||
|    */ | ||||
|   public long getCacheSize() { | ||||
|     return super.getCacheSize(); | ||||
|   } | ||||
| 
 | ||||
|   public static class Builder { | ||||
|     boolean openDiskCache = false; | ||||
|     boolean openMemoryCache = false; | ||||
|     String cacheDirName = DEFAULT_DIR; | ||||
|     long diskCacheSize = NORMAL_DISK_CACHE_CAPACITY; | ||||
|     int memoryCacheSize = MEMORY_CACHE_SIZE; | ||||
|     Context context; | ||||
| 
 | ||||
|     public Builder(Context context) { | ||||
|       this.context = context; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 打开磁盘缓存 | ||||
|      */ | ||||
|     public Builder openDiskCache() { | ||||
|       openDiskCache = true; | ||||
|       return this; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 打开内存缓存 | ||||
|      */ | ||||
|     public Builder openMemoryCache() { | ||||
|       openMemoryCache = true; | ||||
|       return this; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 缓存文件夹名,只需要写文件夹名 | ||||
|      */ | ||||
|     public Builder setCacheDirName(String cacheDirName) { | ||||
|       this.cacheDirName = cacheDirName; | ||||
|       return this; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置磁盘缓存大小 | ||||
|      */ | ||||
|     public Builder setDiskCacheSize(long cacheSize) { | ||||
|       this.diskCacheSize = cacheSize; | ||||
|       return this; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置内存缓存大小 | ||||
|      */ | ||||
|     public Builder setMemoryCacheSize(int cacheSize) { | ||||
|       this.memoryCacheSize = cacheSize; | ||||
|       return this; | ||||
|     } | ||||
| 
 | ||||
|     public CacheUtil build() { | ||||
|       CacheUtil util = new CacheUtil(context); | ||||
|       util.setUseMemoryCache(openMemoryCache); | ||||
|       util.setUseDiskCache(openDiskCache); | ||||
|       util.setMemoryCacheSize(memoryCacheSize); | ||||
|       return new CacheUtil(context, cacheDirName); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,951 @@ | ||||
| /* | ||||
|  * Copyright (C) 2011 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package com.arialyy.frame.cache.diskcache; | ||||
| 
 | ||||
| import java.io.BufferedWriter; | ||||
| import java.io.Closeable; | ||||
| import java.io.EOFException; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.FilterOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.OutputStream; | ||||
| import java.io.OutputStreamWriter; | ||||
| import java.io.Writer; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Iterator; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.Callable; | ||||
| import java.util.concurrent.LinkedBlockingQueue; | ||||
| import java.util.concurrent.ThreadPoolExecutor; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| /** | ||||
|  * A cache that uses a bounded amount of space on a filesystem. Each cache | ||||
|  * entry has a string key and a fixed number of values. Each key must match | ||||
|  * the regex <strong>[a-z0-9_-]{1,120}</strong>. Values are byte sequences, | ||||
|  * accessible as streams or files. Each value must be between {@code 0} and | ||||
|  * {@code Integer.MAX_VALUE} bytes in length. | ||||
|  * | ||||
|  * <p>The cache stores its data in a directory on the filesystem. This | ||||
|  * directory must be exclusive to the cache; the cache may delete or overwrite | ||||
|  * files from its directory. It is an error for multiple processes to use the | ||||
|  * same cache directory at the same time. | ||||
|  * | ||||
|  * <p>This cache limits the number of bytes that it will store on the | ||||
|  * filesystem. When the number of stored bytes exceeds the limit, the cache will | ||||
|  * remove entries in the background until the limit is satisfied. The limit is | ||||
|  * not strict: the cache may temporarily exceed it while waiting for files to be | ||||
|  * deleted. The limit does not include filesystem overhead or the cache | ||||
|  * journal so space-sensitive applications should set a conservative limit. | ||||
|  * | ||||
|  * <p>Clients call {@link #edit} to create or update the values of an entry. An | ||||
|  * entry may have only one editor at one time; if a value is not available to be | ||||
|  * edited then {@link #edit} will return null. | ||||
|  * <ul> | ||||
|  * <li>When an entry is being <strong>created</strong> it is necessary to | ||||
|  * supply a full set of values; the empty value should be used as a | ||||
|  * placeholder if necessary. | ||||
|  * <li>When an entry is being <strong>edited</strong>, it is not necessary | ||||
|  * to supply data for every value; values default to their previous | ||||
|  * value. | ||||
|  * </ul> | ||||
|  * Every {@link #edit} call must be matched by a call to {@link Editor#commit} | ||||
|  * or {@link Editor#abort}. Committing is atomic: a read observes the full set | ||||
|  * of values as they were before or after the commit, but never a mix of values. | ||||
|  * | ||||
|  * <p>Clients call {@link #get} to read a snapshot of an entry. The read will | ||||
|  * observe the value at the time that {@link #get} was called. Updates and | ||||
|  * removals after the call do not impact ongoing reads. | ||||
|  * | ||||
|  * <p>This class is tolerant of some I/O errors. If files are missing from the | ||||
|  * filesystem, the corresponding entries will be dropped from the cache. If | ||||
|  * an error occurs while writing a cache value, the edit will fail silently. | ||||
|  * Callers should handle other problems by catching {@code IOException} and | ||||
|  * responding appropriately. | ||||
|  */ | ||||
| public final class DiskLruCache implements Closeable { | ||||
|   static final String JOURNAL_FILE = "journal"; | ||||
|   static final String JOURNAL_FILE_TEMP = "journal.tmp"; | ||||
|   static final String JOURNAL_FILE_BACKUP = "journal.bkp"; | ||||
|   static final String MAGIC = "libcore.io.DiskLruCache"; | ||||
|   static final String VERSION_1 = "1"; | ||||
|   static final long ANY_SEQUENCE_NUMBER = -1; | ||||
|   static final String STRING_KEY_PATTERN = "[a-z0-9_-]{1,120}"; | ||||
|   static final Pattern LEGAL_KEY_PATTERN = Pattern.compile(STRING_KEY_PATTERN); | ||||
|   private static final String CLEAN = "CLEAN"; | ||||
|   private static final String DIRTY = "DIRTY"; | ||||
|   private static final String REMOVE = "REMOVE"; | ||||
|   private static final String READ = "READ"; | ||||
| 
 | ||||
|     /* | ||||
|      * This cache uses a journal file named "journal". A typical journal file | ||||
|      * looks like this: | ||||
|      *     libcore.io.DiskLruCache | ||||
|      *     1 | ||||
|      *     100 | ||||
|      *     2 | ||||
|      * | ||||
|      *     CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054 | ||||
|      *     DIRTY 335c4c6028171cfddfbaae1a9c313c52 | ||||
|      *     CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342 | ||||
|      *     REMOVE 335c4c6028171cfddfbaae1a9c313c52 | ||||
|      *     DIRTY 1ab96a171faeeee38496d8b330771a7a | ||||
|      *     CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234 | ||||
|      *     READ 335c4c6028171cfddfbaae1a9c313c52 | ||||
|      *     READ 3400330d1dfc7f3f7f4b8d4d803dfcf6 | ||||
|      * | ||||
|      * The first five lines of the journal form its header. They are the | ||||
|      * constant string "libcore.io.DiskLruCache", the disk cache's version, | ||||
|      * the application's version, the value count, and a blank line. | ||||
|      * | ||||
|      * Each of the subsequent lines in the file is a record of the state of a | ||||
|      * cache entry. Each line contains space-separated values: a state, a key, | ||||
|      * and optional state-specific values. | ||||
|      *   o DIRTY lines track that an entry is actively being created or updated. | ||||
|      *     Every successful DIRTY action should be followed by a CLEAN or REMOVE | ||||
|      *     action. DIRTY lines without a matching CLEAN or REMOVE indicate that | ||||
|      *     temporary files may need to be deleted. | ||||
|      *   o CLEAN lines track a cache entry that has been successfully published | ||||
|      *     and may be read. A publish line is followed by the lengths of each of | ||||
|      *     its values. | ||||
|      *   o READ lines track accesses for LRU. | ||||
|      *   o REMOVE lines track entries that have been deleted. | ||||
|      * | ||||
|      * The journal file is appended to as cache operations occur. The journal may | ||||
|      * occasionally be compacted by dropping redundant lines. A temporary file named | ||||
|      * "journal.tmp" will be used during compaction; that file should be deleted if | ||||
|      * it exists when the cache is opened. | ||||
|      */ | ||||
| 
 | ||||
|   private final File directory; | ||||
|   private final File journalFile; | ||||
|   private final File journalFileTmp; | ||||
|   private final File journalFileBackup; | ||||
|   private final int appVersion; | ||||
|   private long maxSize; | ||||
|   private final int valueCount; | ||||
|   private long size = 0; | ||||
|   private Writer journalWriter; | ||||
|   private final LinkedHashMap<String, Entry> lruEntries = | ||||
|       new LinkedHashMap<String, Entry>(0, 0.75f, true); | ||||
|   private int redundantOpCount; | ||||
| 
 | ||||
|   /** | ||||
|    * To differentiate between old and current snapshots, each entry is given | ||||
|    * a sequence number each time an edit is committed. A snapshot is stale if | ||||
|    * its sequence number is not equal to its entry's sequence number. | ||||
|    */ | ||||
|   private long nextSequenceNumber = 0; | ||||
| 
 | ||||
|   /** This cache uses a single background thread to evict entries. */ | ||||
|   final ThreadPoolExecutor executorService = | ||||
|       new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); | ||||
|   private final Callable<Void> cleanupCallable = new Callable<Void>() { | ||||
|     public Void call() throws Exception { | ||||
|       synchronized (DiskLruCache.this) { | ||||
|         if (journalWriter == null) { | ||||
|           return null; // Closed.
 | ||||
|         } | ||||
|         trimToSize(); | ||||
|         if (journalRebuildRequired()) { | ||||
|           rebuildJournal(); | ||||
|           redundantOpCount = 0; | ||||
|         } | ||||
|       } | ||||
|       return null; | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) { | ||||
|     this.directory = directory; | ||||
|     this.appVersion = appVersion; | ||||
|     this.journalFile = new File(directory, JOURNAL_FILE); | ||||
|     this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP); | ||||
|     this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP); | ||||
|     this.valueCount = valueCount; | ||||
|     this.maxSize = maxSize; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Opens the cache in {@code directory}, creating a cache if none exists | ||||
|    * there. | ||||
|    * | ||||
|    * @param directory a writable directory | ||||
|    * @param valueCount the number of values per cache entry. Must be positive. | ||||
|    * @param maxSize the maximum number of bytes this cache should use to store | ||||
|    * @throws IOException if reading or writing the cache directory fails | ||||
|    */ | ||||
|   public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) | ||||
|       throws IOException { | ||||
|     if (maxSize <= 0) { | ||||
|       throw new IllegalArgumentException("maxSize <= 0"); | ||||
|     } | ||||
|     if (valueCount <= 0) { | ||||
|       throw new IllegalArgumentException("valueCount <= 0"); | ||||
|     } | ||||
| 
 | ||||
|     // If a bkp file exists, use it instead.
 | ||||
|     File backupFile = new File(directory, JOURNAL_FILE_BACKUP); | ||||
|     if (backupFile.exists()) { | ||||
|       File journalFile = new File(directory, JOURNAL_FILE); | ||||
|       // If journal file also exists just delete backup file.
 | ||||
|       if (journalFile.exists()) { | ||||
|         backupFile.delete(); | ||||
|       } else { | ||||
|         renameTo(backupFile, journalFile, false); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // Prefer to pick up where we left off.
 | ||||
|     DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); | ||||
|     if (cache.journalFile.exists()) { | ||||
|       try { | ||||
|         cache.readJournal(); | ||||
|         cache.processJournal(); | ||||
|         return cache; | ||||
|       } catch (IOException journalIsCorrupt) { | ||||
|         System.out.println("DiskLruCache " | ||||
|             + directory | ||||
|             + " is corrupt: " | ||||
|             + journalIsCorrupt.getMessage() | ||||
|             + ", removing"); | ||||
|         cache.delete(); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // Create a new empty cache.
 | ||||
|     directory.mkdirs(); | ||||
|     cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); | ||||
|     cache.rebuildJournal(); | ||||
|     return cache; | ||||
|   } | ||||
| 
 | ||||
|   private void readJournal() throws IOException { | ||||
|     StrictLineReader reader = | ||||
|         new StrictLineReader(new FileInputStream(journalFile), DiskLruCacheUtil.US_ASCII); | ||||
|     try { | ||||
|       String magic = reader.readLine(); | ||||
|       String version = reader.readLine(); | ||||
|       String appVersionString = reader.readLine(); | ||||
|       String valueCountString = reader.readLine(); | ||||
|       String blank = reader.readLine(); | ||||
|       if (!MAGIC.equals(magic) || !VERSION_1.equals(version) || !Integer.toString(appVersion) | ||||
|           .equals(appVersionString) || !Integer.toString(valueCount).equals(valueCountString) || !"" | ||||
|           .equals(blank)) { | ||||
|         throw new IOException("unexpected journal header: [" | ||||
|             + magic | ||||
|             + ", " | ||||
|             + version | ||||
|             + ", " | ||||
|             + valueCountString | ||||
|             + ", " | ||||
|             + blank | ||||
|             + "]"); | ||||
|       } | ||||
| 
 | ||||
|       int lineCount = 0; | ||||
|       while (true) { | ||||
|         try { | ||||
|           readJournalLine(reader.readLine()); | ||||
|           lineCount++; | ||||
|         } catch (EOFException endOfJournal) { | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|       redundantOpCount = lineCount - lruEntries.size(); | ||||
| 
 | ||||
|       // If we ended on a truncated line, rebuild the journal before appending to it.
 | ||||
|       if (reader.hasUnterminatedLine()) { | ||||
|         rebuildJournal(); | ||||
|       } else { | ||||
|         journalWriter = new BufferedWriter( | ||||
|             new OutputStreamWriter(new FileOutputStream(journalFile, true), | ||||
|                 DiskLruCacheUtil.US_ASCII)); | ||||
|       } | ||||
|     } finally { | ||||
|       DiskLruCacheUtil.closeQuietly(reader); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private void readJournalLine(String line) throws IOException { | ||||
|     int firstSpace = line.indexOf(' '); | ||||
|     if (firstSpace == -1) { | ||||
|       throw new IOException("unexpected journal line: " + line); | ||||
|     } | ||||
| 
 | ||||
|     int keyBegin = firstSpace + 1; | ||||
|     int secondSpace = line.indexOf(' ', keyBegin); | ||||
|     final String key; | ||||
|     if (secondSpace == -1) { | ||||
|       key = line.substring(keyBegin); | ||||
|       if (firstSpace == REMOVE.length() && line.startsWith(REMOVE)) { | ||||
|         lruEntries.remove(key); | ||||
|         return; | ||||
|       } | ||||
|     } else { | ||||
|       key = line.substring(keyBegin, secondSpace); | ||||
|     } | ||||
| 
 | ||||
|     Entry entry = lruEntries.get(key); | ||||
|     if (entry == null) { | ||||
|       entry = new Entry(key); | ||||
|       lruEntries.put(key, entry); | ||||
|     } | ||||
| 
 | ||||
|     if (secondSpace != -1 && firstSpace == CLEAN.length() && line.startsWith(CLEAN)) { | ||||
|       String[] parts = line.substring(secondSpace + 1).split(" "); | ||||
|       entry.readable = true; | ||||
|       entry.currentEditor = null; | ||||
|       entry.setLengths(parts); | ||||
|     } else if (secondSpace == -1 && firstSpace == DIRTY.length() && line.startsWith(DIRTY)) { | ||||
|       entry.currentEditor = new Editor(entry); | ||||
|     } else if (secondSpace == -1 && firstSpace == READ.length() && line.startsWith(READ)) { | ||||
|       // This work was already done by calling lruEntries.get().
 | ||||
|     } else { | ||||
|       throw new IOException("unexpected journal line: " + line); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Computes the initial size and collects garbage as a part of opening the | ||||
|    * cache. Dirty entries are assumed to be inconsistent and will be deleted. | ||||
|    */ | ||||
|   private void processJournal() throws IOException { | ||||
|     deleteIfExists(journalFileTmp); | ||||
|     for (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) { | ||||
|       Entry entry = i.next(); | ||||
|       if (entry.currentEditor == null) { | ||||
|         for (int t = 0; t < valueCount; t++) { | ||||
|           size += entry.lengths[t]; | ||||
|         } | ||||
|       } else { | ||||
|         entry.currentEditor = null; | ||||
|         for (int t = 0; t < valueCount; t++) { | ||||
|           deleteIfExists(entry.getCleanFile(t)); | ||||
|           deleteIfExists(entry.getDirtyFile(t)); | ||||
|         } | ||||
|         i.remove(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Creates a new journal that omits redundant information. This replaces the | ||||
|    * current journal if it exists. | ||||
|    */ | ||||
|   private synchronized void rebuildJournal() throws IOException { | ||||
|     if (journalWriter != null) { | ||||
|       journalWriter.close(); | ||||
|     } | ||||
| 
 | ||||
|     Writer writer = new BufferedWriter( | ||||
|         new OutputStreamWriter(new FileOutputStream(journalFileTmp), DiskLruCacheUtil.US_ASCII)); | ||||
|     try { | ||||
|       writer.write(MAGIC); | ||||
|       writer.write("\n"); | ||||
|       writer.write(VERSION_1); | ||||
|       writer.write("\n"); | ||||
|       writer.write(Integer.toString(appVersion)); | ||||
|       writer.write("\n"); | ||||
|       writer.write(Integer.toString(valueCount)); | ||||
|       writer.write("\n"); | ||||
|       writer.write("\n"); | ||||
| 
 | ||||
|       for (Entry entry : lruEntries.values()) { | ||||
|         if (entry.currentEditor != null) { | ||||
|           writer.write(DIRTY + ' ' + entry.key + '\n'); | ||||
|         } else { | ||||
|           writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); | ||||
|         } | ||||
|       } | ||||
|     } finally { | ||||
|       writer.close(); | ||||
|     } | ||||
| 
 | ||||
|     if (journalFile.exists()) { | ||||
|       renameTo(journalFile, journalFileBackup, true); | ||||
|     } | ||||
|     renameTo(journalFileTmp, journalFile, false); | ||||
|     journalFileBackup.delete(); | ||||
| 
 | ||||
|     journalWriter = new BufferedWriter( | ||||
|         new OutputStreamWriter(new FileOutputStream(journalFile, true), DiskLruCacheUtil.US_ASCII)); | ||||
|   } | ||||
| 
 | ||||
|   private static void deleteIfExists(File file) throws IOException { | ||||
|     if (file.exists() && !file.delete()) { | ||||
|       throw new IOException(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private static void renameTo(File from, File to, boolean deleteDestination) throws IOException { | ||||
|     if (deleteDestination) { | ||||
|       deleteIfExists(to); | ||||
|     } | ||||
|     if (!from.renameTo(to)) { | ||||
|       throw new IOException(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns a snapshot of the entry named {@code key}, or null if it doesn't | ||||
|    * exist is not currently readable. If a value is returned, it is moved to | ||||
|    * the head of the LRU queue. | ||||
|    */ | ||||
|   public synchronized Snapshot get(String key) throws IOException { | ||||
|     checkNotClosed(); | ||||
|     validateKey(key); | ||||
|     Entry entry = lruEntries.get(key); | ||||
|     if (entry == null) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     if (!entry.readable) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     // Open all streams eagerly to guarantee that we see a single published
 | ||||
|     // snapshot. If we opened streams lazily then the streams could come
 | ||||
|     // from different edits.
 | ||||
|     InputStream[] ins = new InputStream[valueCount]; | ||||
|     try { | ||||
|       for (int i = 0; i < valueCount; i++) { | ||||
|         ins[i] = new FileInputStream(entry.getCleanFile(i)); | ||||
|       } | ||||
|     } catch (FileNotFoundException e) { | ||||
|       // A file must have been deleted manually!
 | ||||
|       for (int i = 0; i < valueCount; i++) { | ||||
|         if (ins[i] != null) { | ||||
|           DiskLruCacheUtil.closeQuietly(ins[i]); | ||||
|         } else { | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     redundantOpCount++; | ||||
|     journalWriter.append(READ + ' ' + key + '\n'); | ||||
|     if (journalRebuildRequired()) { | ||||
|       executorService.submit(cleanupCallable); | ||||
|     } | ||||
| 
 | ||||
|     return new Snapshot(key, entry.sequenceNumber, ins, entry.lengths); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns an editor for the entry named {@code key}, or null if another | ||||
|    * edit is in progress. | ||||
|    */ | ||||
|   public Editor edit(String key) throws IOException { | ||||
|     return edit(key, ANY_SEQUENCE_NUMBER); | ||||
|   } | ||||
| 
 | ||||
|   private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { | ||||
|     checkNotClosed(); | ||||
|     validateKey(key); | ||||
|     Entry entry = lruEntries.get(key); | ||||
|     if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null | ||||
|         || entry.sequenceNumber != expectedSequenceNumber)) { | ||||
|       return null; // Snapshot is stale.
 | ||||
|     } | ||||
|     if (entry == null) { | ||||
|       entry = new Entry(key); | ||||
|       lruEntries.put(key, entry); | ||||
|     } else if (entry.currentEditor != null) { | ||||
|       return null; // Another edit is in progress.
 | ||||
|     } | ||||
| 
 | ||||
|     Editor editor = new Editor(entry); | ||||
|     entry.currentEditor = editor; | ||||
| 
 | ||||
|     // Flush the journal before creating files to prevent file leaks.
 | ||||
|     journalWriter.write(DIRTY + ' ' + key + '\n'); | ||||
|     journalWriter.flush(); | ||||
|     return editor; | ||||
|   } | ||||
| 
 | ||||
|   /** Returns the directory where this cache stores its data. */ | ||||
|   public File getDirectory() { | ||||
|     return directory; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the maximum number of bytes that this cache should use to store | ||||
|    * its data. | ||||
|    */ | ||||
|   public synchronized long getMaxSize() { | ||||
|     return maxSize; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Changes the maximum number of bytes the cache can store and queues a job | ||||
|    * to trim the existing store, if necessary. | ||||
|    */ | ||||
|   public synchronized void setMaxSize(long maxSize) { | ||||
|     this.maxSize = maxSize; | ||||
|     executorService.submit(cleanupCallable); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the number of bytes currently being used to store the values in | ||||
|    * this cache. This may be greater than the max size if a background | ||||
|    * deletion is pending. | ||||
|    */ | ||||
|   public synchronized long size() { | ||||
|     return size; | ||||
|   } | ||||
| 
 | ||||
|   private synchronized void completeEdit(Editor editor, boolean success) throws IOException { | ||||
|     Entry entry = editor.entry; | ||||
|     if (entry.currentEditor != editor) { | ||||
|       throw new IllegalStateException(); | ||||
|     } | ||||
| 
 | ||||
|     // If this edit is creating the entry for the first time, every index must have a value.
 | ||||
|     if (success && !entry.readable) { | ||||
|       for (int i = 0; i < valueCount; i++) { | ||||
|         if (!editor.written[i]) { | ||||
|           editor.abort(); | ||||
|           throw new IllegalStateException("Newly created entry didn't create value for index " + i); | ||||
|         } | ||||
|         if (!entry.getDirtyFile(i).exists()) { | ||||
|           editor.abort(); | ||||
|           return; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     for (int i = 0; i < valueCount; i++) { | ||||
|       File dirty = entry.getDirtyFile(i); | ||||
|       if (success) { | ||||
|         if (dirty.exists()) { | ||||
|           File clean = entry.getCleanFile(i); | ||||
|           dirty.renameTo(clean); | ||||
|           long oldLength = entry.lengths[i]; | ||||
|           long newLength = clean.length(); | ||||
|           entry.lengths[i] = newLength; | ||||
|           size = size - oldLength + newLength; | ||||
|         } | ||||
|       } else { | ||||
|         deleteIfExists(dirty); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     redundantOpCount++; | ||||
|     entry.currentEditor = null; | ||||
|     if (entry.readable | success) { | ||||
|       entry.readable = true; | ||||
|       journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); | ||||
|       if (success) { | ||||
|         entry.sequenceNumber = nextSequenceNumber++; | ||||
|       } | ||||
|     } else { | ||||
|       lruEntries.remove(entry.key); | ||||
|       journalWriter.write(REMOVE + ' ' + entry.key + '\n'); | ||||
|     } | ||||
|     journalWriter.flush(); | ||||
| 
 | ||||
|     if (size > maxSize || journalRebuildRequired()) { | ||||
|       executorService.submit(cleanupCallable); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * We only rebuild the journal when it will halve the size of the journal | ||||
|    * and eliminate at least 2000 ops. | ||||
|    */ | ||||
|   private boolean journalRebuildRequired() { | ||||
|     final int redundantOpCompactThreshold = 2000; | ||||
|     return redundantOpCount >= redundantOpCompactThreshold //
 | ||||
|         && redundantOpCount >= lruEntries.size(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Drops the entry for {@code key} if it exists and can be removed. Entries | ||||
|    * actively being edited cannot be removed. | ||||
|    * | ||||
|    * @return true if an entry was removed. | ||||
|    */ | ||||
|   public synchronized boolean remove(String key) throws IOException { | ||||
|     checkNotClosed(); | ||||
|     validateKey(key); | ||||
|     Entry entry = lruEntries.get(key); | ||||
|     if (entry == null || entry.currentEditor != null) { | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     for (int i = 0; i < valueCount; i++) { | ||||
|       File file = entry.getCleanFile(i); | ||||
|       if (file.exists() && !file.delete()) { | ||||
|         throw new IOException("failed to delete " + file); | ||||
|       } | ||||
|       size -= entry.lengths[i]; | ||||
|       entry.lengths[i] = 0; | ||||
|     } | ||||
| 
 | ||||
|     redundantOpCount++; | ||||
|     journalWriter.append(REMOVE + ' ' + key + '\n'); | ||||
|     lruEntries.remove(key); | ||||
| 
 | ||||
|     if (journalRebuildRequired()) { | ||||
|       executorService.submit(cleanupCallable); | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   /** Returns true if this cache has been closed. */ | ||||
|   public synchronized boolean isClosed() { | ||||
|     return journalWriter == null; | ||||
|   } | ||||
| 
 | ||||
|   private void checkNotClosed() { | ||||
|     if (journalWriter == null) { | ||||
|       throw new IllegalStateException("cache is closed"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** Force buffered operations to the filesystem. */ | ||||
|   public synchronized void flush() throws IOException { | ||||
|     checkNotClosed(); | ||||
|     trimToSize(); | ||||
|     journalWriter.flush(); | ||||
|   } | ||||
| 
 | ||||
|   /** Closes this cache. Stored values will remain on the filesystem. */ | ||||
|   public synchronized void close() throws IOException { | ||||
|     if (journalWriter == null) { | ||||
|       return; // Already closed.
 | ||||
|     } | ||||
|     for (Entry entry : new ArrayList<Entry>(lruEntries.values())) { | ||||
|       if (entry.currentEditor != null) { | ||||
|         entry.currentEditor.abort(); | ||||
|       } | ||||
|     } | ||||
|     trimToSize(); | ||||
|     journalWriter.close(); | ||||
|     journalWriter = null; | ||||
|   } | ||||
| 
 | ||||
|   private void trimToSize() throws IOException { | ||||
|     while (size > maxSize) { | ||||
|       Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next(); | ||||
|       remove(toEvict.getKey()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Closes the cache and deletes all of its stored values. This will delete | ||||
|    * all files in the cache directory including files that weren't created by | ||||
|    * the cache. | ||||
|    */ | ||||
|   public void delete() throws IOException { | ||||
|     close(); | ||||
|     DiskLruCacheUtil.deleteContents(directory); | ||||
|   } | ||||
| 
 | ||||
|   private void validateKey(String key) { | ||||
|     Matcher matcher = LEGAL_KEY_PATTERN.matcher(key); | ||||
|     if (!matcher.matches()) { | ||||
|       throw new IllegalArgumentException( | ||||
|           "keys must match regex " + STRING_KEY_PATTERN + ": \"" + key + "\""); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private static String inputStreamToString(InputStream in) throws IOException { | ||||
|     return DiskLruCacheUtil.readFully(new InputStreamReader(in, DiskLruCacheUtil.UTF_8)); | ||||
|   } | ||||
| 
 | ||||
|   /** A snapshot of the values for an entry. */ | ||||
|   public final class Snapshot implements Closeable { | ||||
|     private final String key; | ||||
|     private final long sequenceNumber; | ||||
|     private final InputStream[] ins; | ||||
|     private final long[] lengths; | ||||
| 
 | ||||
|     private Snapshot(String key, long sequenceNumber, InputStream[] ins, long[] lengths) { | ||||
|       this.key = key; | ||||
|       this.sequenceNumber = sequenceNumber; | ||||
|       this.ins = ins; | ||||
|       this.lengths = lengths; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns an editor for this snapshot's entry, or null if either the | ||||
|      * entry has changed since this snapshot was created or if another edit | ||||
|      * is in progress. | ||||
|      */ | ||||
|     public Editor edit() throws IOException { | ||||
|       return DiskLruCache.this.edit(key, sequenceNumber); | ||||
|     } | ||||
| 
 | ||||
|     /** Returns the unbuffered stream with the value for {@code index}. */ | ||||
|     public InputStream getInputStream(int index) { | ||||
|       return ins[index]; | ||||
|     } | ||||
| 
 | ||||
|     /** Returns the string value for {@code index}. */ | ||||
|     public String getString(int index) throws IOException { | ||||
|       return inputStreamToString(getInputStream(index)); | ||||
|     } | ||||
| 
 | ||||
|     /** Returns the byte length of the value for {@code index}. */ | ||||
|     public long getLength(int index) { | ||||
|       return lengths[index]; | ||||
|     } | ||||
| 
 | ||||
|     public void close() { | ||||
|       for (InputStream in : ins) { | ||||
|         DiskLruCacheUtil.closeQuietly(in); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private static final OutputStream NULL_OUTPUT_STREAM = new OutputStream() { | ||||
|     @Override public void write(int b) throws IOException { | ||||
|       // Eat all writes silently. Nom nom.
 | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   /** Edits the values for an entry. */ | ||||
|   public final class Editor { | ||||
|     private final Entry entry; | ||||
|     private final boolean[] written; | ||||
|     private boolean hasErrors; | ||||
|     private boolean committed; | ||||
| 
 | ||||
|     private Editor(Entry entry) { | ||||
|       this.entry = entry; | ||||
|       this.written = (entry.readable) ? null : new boolean[valueCount]; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns an unbuffered input stream to read the last committed value, | ||||
|      * or null if no value has been committed. | ||||
|      */ | ||||
|     public InputStream newInputStream(int index) throws IOException { | ||||
|       synchronized (DiskLruCache.this) { | ||||
|         if (entry.currentEditor != this) { | ||||
|           throw new IllegalStateException(); | ||||
|         } | ||||
|         if (!entry.readable) { | ||||
|           return null; | ||||
|         } | ||||
|         try { | ||||
|           return new FileInputStream(entry.getCleanFile(index)); | ||||
|         } catch (FileNotFoundException e) { | ||||
|           return null; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the last committed value as a string, or null if no value | ||||
|      * has been committed. | ||||
|      */ | ||||
|     public String getString(int index) throws IOException { | ||||
|       InputStream in = newInputStream(index); | ||||
|       return in != null ? inputStreamToString(in) : null; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns a new unbuffered output stream to write the value at | ||||
|      * {@code index}. If the underlying output stream encounters errors | ||||
|      * when writing to the filesystem, this edit will be aborted when | ||||
|      * {@link #commit} is called. The returned output stream does not throw | ||||
|      * IOExceptions. | ||||
|      */ | ||||
|     public OutputStream newOutputStream(int index) throws IOException { | ||||
|       if (index < 0 || index >= valueCount) { | ||||
|         throw new IllegalArgumentException("Expected index " | ||||
|             + index | ||||
|             + " to " | ||||
|             + "be greater than 0 and less than the maximum value count " | ||||
|             + "of " | ||||
|             + valueCount); | ||||
|       } | ||||
|       synchronized (DiskLruCache.this) { | ||||
|         if (entry.currentEditor != this) { | ||||
|           throw new IllegalStateException(); | ||||
|         } | ||||
|         if (!entry.readable) { | ||||
|           written[index] = true; | ||||
|         } | ||||
|         File dirtyFile = entry.getDirtyFile(index); | ||||
|         FileOutputStream outputStream; | ||||
|         try { | ||||
|           outputStream = new FileOutputStream(dirtyFile); | ||||
|         } catch (FileNotFoundException e) { | ||||
|           // Attempt to recreate the cache directory.
 | ||||
|           directory.mkdirs(); | ||||
|           try { | ||||
|             outputStream = new FileOutputStream(dirtyFile); | ||||
|           } catch (FileNotFoundException e2) { | ||||
|             // We are unable to recover. Silently eat the writes.
 | ||||
|             return NULL_OUTPUT_STREAM; | ||||
|           } | ||||
|         } | ||||
|         return new FaultHidingOutputStream(outputStream); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     /** Sets the value at {@code index} to {@code value}. */ | ||||
|     public void set(int index, String value) throws IOException { | ||||
|       Writer writer = null; | ||||
|       try { | ||||
|         writer = new OutputStreamWriter(newOutputStream(index), DiskLruCacheUtil.UTF_8); | ||||
|         writer.write(value); | ||||
|       } finally { | ||||
|         DiskLruCacheUtil.closeQuietly(writer); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Commits this edit so it is visible to readers.  This releases the | ||||
|      * edit lock so another edit may be started on the same key. | ||||
|      */ | ||||
|     public void commit() throws IOException { | ||||
|       if (hasErrors) { | ||||
|         completeEdit(this, false); | ||||
|         remove(entry.key); // The previous entry is stale.
 | ||||
|       } else { | ||||
|         completeEdit(this, true); | ||||
|       } | ||||
|       committed = true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Aborts this edit. This releases the edit lock so another edit may be | ||||
|      * started on the same key. | ||||
|      */ | ||||
|     public void abort() throws IOException { | ||||
|       completeEdit(this, false); | ||||
|     } | ||||
| 
 | ||||
|     public void abortUnlessCommitted() { | ||||
|       if (!committed) { | ||||
|         try { | ||||
|           abort(); | ||||
|         } catch (IOException ignored) { | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     private class FaultHidingOutputStream extends FilterOutputStream { | ||||
|       private FaultHidingOutputStream(OutputStream out) { | ||||
|         super(out); | ||||
|       } | ||||
| 
 | ||||
|       @Override public void write(int oneByte) { | ||||
|         try { | ||||
|           out.write(oneByte); | ||||
|         } catch (IOException e) { | ||||
|           hasErrors = true; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       @Override public void write(byte[] buffer, int offset, int length) { | ||||
|         try { | ||||
|           out.write(buffer, offset, length); | ||||
|         } catch (IOException e) { | ||||
|           hasErrors = true; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       @Override public void close() { | ||||
|         try { | ||||
|           out.close(); | ||||
|         } catch (IOException e) { | ||||
|           hasErrors = true; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       @Override public void flush() { | ||||
|         try { | ||||
|           out.flush(); | ||||
|         } catch (IOException e) { | ||||
|           hasErrors = true; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private final class Entry { | ||||
|     private final String key; | ||||
| 
 | ||||
|     /** Lengths of this entry's files. */ | ||||
|     private final long[] lengths; | ||||
| 
 | ||||
|     /** True if this entry has ever been published. */ | ||||
|     private boolean readable; | ||||
| 
 | ||||
|     /** The ongoing edit or null if this entry is not being edited. */ | ||||
|     private Editor currentEditor; | ||||
| 
 | ||||
|     /** The sequence number of the most recently committed edit to this entry. */ | ||||
|     private long sequenceNumber; | ||||
| 
 | ||||
|     private Entry(String key) { | ||||
|       this.key = key; | ||||
|       this.lengths = new long[valueCount]; | ||||
|     } | ||||
| 
 | ||||
|     public String getLengths() throws IOException { | ||||
|       StringBuilder result = new StringBuilder(); | ||||
|       for (long size : lengths) { | ||||
|         result.append(' ').append(size); | ||||
|       } | ||||
|       return result.toString(); | ||||
|     } | ||||
| 
 | ||||
|     /** Set lengths using decimal numbers like "10123". */ | ||||
|     private void setLengths(String[] strings) throws IOException { | ||||
|       if (strings.length != valueCount) { | ||||
|         throw invalidLengths(strings); | ||||
|       } | ||||
| 
 | ||||
|       try { | ||||
|         for (int i = 0; i < strings.length; i++) { | ||||
|           lengths[i] = Long.parseLong(strings[i]); | ||||
|         } | ||||
|       } catch (NumberFormatException e) { | ||||
|         throw invalidLengths(strings); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     private IOException invalidLengths(String[] strings) throws IOException { | ||||
|       throw new IOException("unexpected journal line: " + java.util.Arrays.toString(strings)); | ||||
|     } | ||||
| 
 | ||||
|     public File getCleanFile(int i) { | ||||
|       return new File(directory, key + "." + i); | ||||
|     } | ||||
| 
 | ||||
|     public File getDirtyFile(int i) { | ||||
|       return new File(directory, key + "." + i + ".tmp"); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,77 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package com.arialyy.frame.cache.diskcache; | ||||
| 
 | ||||
| import java.io.Closeable; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.Reader; | ||||
| import java.io.StringWriter; | ||||
| import java.nio.charset.Charset; | ||||
| 
 | ||||
| /** Junk drawer of utility methods. */ | ||||
| final class DiskLruCacheUtil { | ||||
|   static final Charset US_ASCII = Charset.forName("US-ASCII"); | ||||
|   static final Charset UTF_8 = Charset.forName("UTF-8"); | ||||
| 
 | ||||
|   private DiskLruCacheUtil() { | ||||
|   } | ||||
| 
 | ||||
|   static String readFully(Reader reader) throws IOException { | ||||
|     try { | ||||
|       StringWriter writer = new StringWriter(); | ||||
|       char[] buffer = new char[1024]; | ||||
|       int count; | ||||
|       while ((count = reader.read(buffer)) != -1) { | ||||
|         writer.write(buffer, 0, count); | ||||
|       } | ||||
|       return writer.toString(); | ||||
|     } finally { | ||||
|       reader.close(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Deletes the contents of {@code dir}. Throws an IOException if any file | ||||
|    * could not be deleted, or if {@code dir} is not a readable directory. | ||||
|    */ | ||||
|   static void deleteContents(File dir) throws IOException { | ||||
|     File[] files = dir.listFiles(); | ||||
|     if (files == null) { | ||||
|       throw new IOException("not a readable directory: " + dir); | ||||
|     } | ||||
|     for (File file : files) { | ||||
|       if (file.isDirectory()) { | ||||
|         deleteContents(file); | ||||
|       } | ||||
|       if (!file.delete()) { | ||||
|         throw new IOException("failed to delete file: " + file); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   static void closeQuietly(/*Auto*/Closeable closeable) { | ||||
|     if (closeable != null) { | ||||
|       try { | ||||
|         closeable.close(); | ||||
|       } catch (RuntimeException rethrown) { | ||||
|         throw rethrown; | ||||
|       } catch (Exception ignored) { | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,194 @@ | ||||
| /* | ||||
|  * Copyright (C) 2012 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package com.arialyy.frame.cache.diskcache; | ||||
| 
 | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.Closeable; | ||||
| import java.io.EOFException; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.nio.charset.Charset; | ||||
| 
 | ||||
| /** | ||||
|  * Buffers input from an {@link InputStream} for reading lines. | ||||
|  * | ||||
|  * <p>This class is used for buffered reading of lines. For purposes of this class, a line ends | ||||
|  * with "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated | ||||
|  * line at end of input is invalid and will be ignored, the caller may use {@code | ||||
|  * hasUnterminatedLine()} to detect it after catching the {@code EOFException}. | ||||
|  * | ||||
|  * <p>This class is intended for reading input that strictly consists of lines, such as line-based | ||||
|  * cache entries or cache journal. Unlike the {@link java.io.BufferedReader} which in conjunction | ||||
|  * with {@link java.io.InputStreamReader} provides similar functionality, this class uses different | ||||
|  * end-of-input reporting and a more restrictive definition of a line. | ||||
|  * | ||||
|  * <p>This class supports only charsets that encode '\r' and '\n' as a single byte with value 13 | ||||
|  * and 10, respectively, and the representation of no other character contains these values. | ||||
|  * We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1. | ||||
|  * The default charset is US_ASCII. | ||||
|  */ | ||||
| class StrictLineReader implements Closeable { | ||||
|   private static final byte CR = (byte) '\r'; | ||||
|   private static final byte LF = (byte) '\n'; | ||||
| 
 | ||||
|   private final InputStream in; | ||||
|   private final Charset charset; | ||||
| 
 | ||||
|   /* | ||||
|    * Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end | ||||
|    * and the data in the range [pos, end) is buffered for reading. At end of input, if there is | ||||
|    * an unterminated line, we set end == -1, otherwise end == pos. If the underlying | ||||
|    * {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1. | ||||
|    */ | ||||
|   private byte[] buf; | ||||
|   private int pos; | ||||
|   private int end; | ||||
| 
 | ||||
|   /** | ||||
|    * Constructs a new {@code LineReader} with the specified charset and the default capacity. | ||||
|    * | ||||
|    * @param in the {@code InputStream} to read data from. | ||||
|    * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are | ||||
|    * supported. | ||||
|    * @throws NullPointerException if {@code in} or {@code charset} is null. | ||||
|    * @throws IllegalArgumentException if the specified charset is not supported. | ||||
|    */ | ||||
|   public StrictLineReader(InputStream in, Charset charset) { | ||||
|     this(in, 8192, charset); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Constructs a new {@code LineReader} with the specified capacity and charset. | ||||
|    * | ||||
|    * @param in the {@code InputStream} to read data from. | ||||
|    * @param capacity the capacity of the buffer. | ||||
|    * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are | ||||
|    * supported. | ||||
|    * @throws NullPointerException if {@code in} or {@code charset} is null. | ||||
|    * @throws IllegalArgumentException if {@code capacity} is negative or zero | ||||
|    * or the specified charset is not supported. | ||||
|    */ | ||||
|   public StrictLineReader(InputStream in, int capacity, Charset charset) { | ||||
|     if (in == null || charset == null) { | ||||
|       throw new NullPointerException(); | ||||
|     } | ||||
|     if (capacity < 0) { | ||||
|       throw new IllegalArgumentException("capacity <= 0"); | ||||
|     } | ||||
|     if (!(charset.equals(DiskLruCacheUtil.US_ASCII))) { | ||||
|       throw new IllegalArgumentException("Unsupported encoding"); | ||||
|     } | ||||
| 
 | ||||
|     this.in = in; | ||||
|     this.charset = charset; | ||||
|     buf = new byte[capacity]; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Closes the reader by closing the underlying {@code InputStream} and | ||||
|    * marking this reader as closed. | ||||
|    * | ||||
|    * @throws IOException for errors when closing the underlying {@code InputStream}. | ||||
|    */ | ||||
|   public void close() throws IOException { | ||||
|     synchronized (in) { | ||||
|       if (buf != null) { | ||||
|         buf = null; | ||||
|         in.close(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"}, | ||||
|    * this end of line marker is not included in the result. | ||||
|    * | ||||
|    * @return the next line from the input. | ||||
|    * @throws IOException for underlying {@code InputStream} errors. | ||||
|    * @throws EOFException for the end of source stream. | ||||
|    */ | ||||
|   public String readLine() throws IOException { | ||||
|     synchronized (in) { | ||||
|       if (buf == null) { | ||||
|         throw new IOException("LineReader is closed"); | ||||
|       } | ||||
| 
 | ||||
|       // Read more data if we are at the end of the buffered data.
 | ||||
|       // Though it's an error to read after an exception, we will let {@code fillBuf()}
 | ||||
|       // throw again if that happens; thus we need to handle end == -1 as well as end == pos.
 | ||||
|       if (pos >= end) { | ||||
|         fillBuf(); | ||||
|       } | ||||
|       // Try to find LF in the buffered data and return the line if successful.
 | ||||
|       for (int i = pos; i != end; ++i) { | ||||
|         if (buf[i] == LF) { | ||||
|           int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i; | ||||
|           String res = new String(buf, pos, lineEnd - pos, charset.name()); | ||||
|           pos = i + 1; | ||||
|           return res; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       // Let's anticipate up to 80 characters on top of those already read.
 | ||||
|       ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) { | ||||
|         @Override public String toString() { | ||||
|           int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count; | ||||
|           try { | ||||
|             return new String(buf, 0, length, charset.name()); | ||||
|           } catch (UnsupportedEncodingException e) { | ||||
|             throw new AssertionError(e); // Since we control the charset this will never happen.
 | ||||
|           } | ||||
|         } | ||||
|       }; | ||||
| 
 | ||||
|       while (true) { | ||||
|         out.write(buf, pos, end - pos); | ||||
|         // Mark unterminated line in case fillBuf throws EOFException or IOException.
 | ||||
|         end = -1; | ||||
|         fillBuf(); | ||||
|         // Try to find LF in the buffered data and return the line if successful.
 | ||||
|         for (int i = pos; i != end; ++i) { | ||||
|           if (buf[i] == LF) { | ||||
|             if (i != pos) { | ||||
|               out.write(buf, pos, i - pos); | ||||
|             } | ||||
|             pos = i + 1; | ||||
|             return out.toString(); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public boolean hasUnterminatedLine() { | ||||
|     return end == -1; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Reads new input data into the buffer. Call only with pos == end or end == -1, | ||||
|    * depending on the desired outcome if the function throws. | ||||
|    */ | ||||
|   private void fillBuf() throws IOException { | ||||
|     int result = in.read(buf, 0, buf.length); | ||||
|     if (result == -1) { | ||||
|       throw new EOFException(); | ||||
|     } | ||||
|     pos = 0; | ||||
|     end = result; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,242 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.content.Intent; | ||||
| import android.databinding.DataBindingUtil; | ||||
| import android.databinding.ViewDataBinding; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.v7.app.AppCompatActivity; | ||||
| import android.view.View; | ||||
| import com.arialyy.frame.module.AbsModule; | ||||
| import com.arialyy.frame.module.IOCProxy; | ||||
| import com.arialyy.frame.temp.AbsTempView; | ||||
| import com.arialyy.frame.temp.OnTempBtClickListener; | ||||
| import com.arialyy.frame.temp.TempView; | ||||
| import com.arialyy.frame.util.StringUtil; | ||||
| import com.arialyy.frame.util.show.T; | ||||
| 
 | ||||
| /** | ||||
|  * Created by “AriaLyy@outlook.com” on 2015/11/3. | ||||
|  * 所有的 Activity都应该继承这个类 | ||||
|  */ | ||||
| public abstract class AbsActivity<VB extends ViewDataBinding> extends AppCompatActivity | ||||
|     implements OnTempBtClickListener { | ||||
|   protected String TAG = ""; | ||||
|   protected AbsFrame mAm; | ||||
|   protected View mRootView; | ||||
|   protected AbsTempView mTempView; | ||||
|   protected boolean useTempView = true; | ||||
|   private VB mBind; | ||||
|   private IOCProxy mProxy; | ||||
|   /** | ||||
|    * 第一次点击返回的系统时间 | ||||
|    */ | ||||
|   private long mFirstClickTime = 0; | ||||
|   private ModuleFactory mModuleF; | ||||
| 
 | ||||
|   @Override protected void onCreate(Bundle savedInstanceState) { | ||||
|     super.onCreate(savedInstanceState); | ||||
|     initialization(); | ||||
|     init(savedInstanceState); | ||||
|   } | ||||
| 
 | ||||
|   private void initialization() { | ||||
|     mAm = AbsFrame.getInstance(); | ||||
|     mAm.addActivity(this); | ||||
|     mBind = DataBindingUtil.setContentView(this, setLayoutId()); | ||||
|     mProxy = IOCProxy.newInstance(this); | ||||
|     TAG = StringUtil.getClassName(this); | ||||
|     mModuleF = ModuleFactory.newInstance(); | ||||
|     mRootView = mBind.getRoot(); | ||||
|     if (useTempView) { | ||||
|       mTempView = new TempView(this); | ||||
|       mTempView.setBtListener(this); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   protected void reNewModule() { | ||||
|     if (mModuleF == null) { | ||||
|       mModuleF = ModuleFactory.newInstance(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取填充View | ||||
|    */ | ||||
|   protected AbsTempView getTempView() { | ||||
|     return mTempView; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 是否使用填充界面 | ||||
|    */ | ||||
|   protected void setUseTempView(boolean useTempView) { | ||||
|     this.useTempView = useTempView; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置自定义的TempView | ||||
|    */ | ||||
|   protected void setCustomTempView(AbsTempView tempView) { | ||||
|     mTempView = tempView; | ||||
|     mTempView.setBtListener(this); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 显示占位布局 | ||||
|    * | ||||
|    * @param type {@link TempView#ERROR} | ||||
|    * {@link TempView#DATA_NULL} | ||||
|    * {@link TempView#LOADING} | ||||
|    */ | ||||
|   protected void showTempView(int type) { | ||||
|     if (mTempView == null || !useTempView) { | ||||
|       return; | ||||
|     } | ||||
|     mTempView.setVisibility(View.VISIBLE); | ||||
|     mTempView.setType(type); | ||||
|     setContentView(mTempView); | ||||
|   } | ||||
| 
 | ||||
|   public ModuleFactory getModuleFactory() { | ||||
|     return mModuleF; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 关闭占位布局 | ||||
|    */ | ||||
|   protected void hintTempView() { | ||||
|     hintTempView(0); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 延时关闭占位布局 | ||||
|    */ | ||||
|   protected void hintTempView(int delay) { | ||||
|     new Handler().postDelayed(new Runnable() { | ||||
|       @Override public void run() { | ||||
|         if (mTempView == null || !useTempView) { | ||||
|           return; | ||||
|         } | ||||
|         mTempView.clearFocus(); | ||||
|         mTempView.setVisibility(View.GONE); | ||||
|         setContentView(mRootView); | ||||
|       } | ||||
|     }, delay); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onBtTempClick(View view, int type) { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   @Override protected void onDestroy() { | ||||
|     super.onDestroy(); | ||||
|   } | ||||
| 
 | ||||
|   protected void init(Bundle savedInstanceState) { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   @Override public void finish() { | ||||
|     super.finish(); | ||||
|     mAm.removeActivity(this); | ||||
|   } | ||||
| 
 | ||||
|   public View getRootView() { | ||||
|     return mRootView; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置资源布局 | ||||
|    */ | ||||
|   protected abstract int setLayoutId(); | ||||
| 
 | ||||
|   /** | ||||
|    * 获取binding对象 | ||||
|    */ | ||||
|   protected VB getBinding() { | ||||
|     return mBind; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz) { | ||||
|     M module = mModuleF.getModule(this, clazz); | ||||
|     module.setHost(this); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz Module class0 | ||||
|    * @param callback Module回调函数 | ||||
|    * @param <M> {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz, | ||||
|       @NonNull AbsModule.OnCallback callback) { | ||||
|     M module = mModuleF.getModule(this, clazz); | ||||
|     module.setCallback(callback); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 数据回调 | ||||
|    */ | ||||
|   protected abstract void dataCallback(int result, Object data); | ||||
| 
 | ||||
|   /** | ||||
|    * 双击退出 | ||||
|    */ | ||||
|   private boolean onDoubleClickExit(long timeSpace) { | ||||
|     long currentTimeMillis = System.currentTimeMillis(); | ||||
|     if (currentTimeMillis - mFirstClickTime > timeSpace) { | ||||
|       T.showShort(this, "再按一次退出"); | ||||
|       mFirstClickTime = currentTimeMillis; | ||||
|       return false; | ||||
|     } else { | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 双击退出,间隔时间为2000ms | ||||
|    */ | ||||
|   public boolean onDoubleClickExit() { | ||||
|     return onDoubleClickExit(2000); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 退出应用程序 | ||||
|    * | ||||
|    * @param isBackground 是否开开启后台运行,如果为true则为后台运行 | ||||
|    */ | ||||
|   public void exitApp(Boolean isBackground) { | ||||
|     mAm.exitApp(isBackground); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 退出应用程序 | ||||
|    */ | ||||
|   public void exitApp() { | ||||
|     mAm.exitApp(false); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, | ||||
|       @NonNull int[] grantResults) { | ||||
|     super.onRequestPermissionsResult(requestCode, permissions, grantResults); | ||||
|     PermissionHelp.getInstance().handlePermissionCallback(requestCode, permissions, grantResults); | ||||
|   } | ||||
| 
 | ||||
|   @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { | ||||
|     super.onActivityResult(requestCode, resultCode, data); | ||||
|     PermissionHelp.getInstance() | ||||
|         .handleSpecialPermissionCallback(this, requestCode, resultCode, data); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,112 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.app.Dialog; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| 
 | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.v4.app.DialogFragment; | ||||
| import com.arialyy.frame.module.AbsModule; | ||||
| import com.arialyy.frame.module.IOCProxy; | ||||
| import com.arialyy.frame.util.StringUtil; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2015/11/4. | ||||
|  * AlertDialog基类,具有5.0效果,需要配合 AlertDialog.Builder使用 | ||||
|  */ | ||||
| public abstract class AbsAlertDialog extends DialogFragment { | ||||
|   protected String TAG = ""; | ||||
| 
 | ||||
|   private Object mObj;    //被观察者
 | ||||
|   private IOCProxy mProxy; | ||||
|   private DialogSimpleModule mSimpleModule; | ||||
|   private Dialog mDialog; | ||||
|   private ModuleFactory mModuleF; | ||||
| 
 | ||||
|   public AbsAlertDialog() { | ||||
|     this(null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * @param obj 被观察的对象 | ||||
|    */ | ||||
|   public AbsAlertDialog(Object obj) { | ||||
|     mObj = obj; | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onCreate(Bundle savedInstanceState) { | ||||
|     super.onCreate(savedInstanceState); | ||||
|     initDialog(); | ||||
|   } | ||||
| 
 | ||||
|   @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { | ||||
|     return mDialog; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 创建AlertDialog | ||||
|    * 建议使用AppCompatDialog,该Dialog具有5.0的效果 | ||||
|    */ | ||||
|   public abstract Dialog initAlertDialog(); | ||||
| 
 | ||||
|   private void initDialog() { | ||||
|     TAG = StringUtil.getClassName(this); | ||||
|     mProxy = IOCProxy.newInstance(this); | ||||
|     if (mObj != null) { | ||||
|       mSimpleModule = new DialogSimpleModule(getContext()); | ||||
|       IOCProxy.newInstance(mObj, mSimpleModule); | ||||
|     } | ||||
|     mModuleF = ModuleFactory.newInstance(); | ||||
|     mDialog = initAlertDialog(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(Class<M> clazz) { | ||||
|     M module = mModuleF.getModule(getContext(), clazz); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz Module class0 | ||||
|    * @param callback Module回调函数 | ||||
|    * @param <M> {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz, | ||||
|       @NonNull AbsModule.OnCallback callback) { | ||||
|     M module = mModuleF.getModule(getContext(), clazz); | ||||
|     module.setCallback(callback); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取简单打Moduel回调,这个一般用于回调数据给寄主 | ||||
|    */ | ||||
|   protected DialogSimpleModule getSimplerModule() { | ||||
|     if (mObj == null) { | ||||
|       throw new NullPointerException("必须设置寄主对象"); | ||||
|     } | ||||
|     return mSimpleModule; | ||||
|   } | ||||
| 
 | ||||
|   protected abstract void dataCallback(int result, Object obj); | ||||
| 
 | ||||
|   @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, | ||||
|       @NonNull int[] grantResults) { | ||||
|     super.onRequestPermissionsResult(requestCode, permissions, grantResults); | ||||
|     PermissionHelp.getInstance().handlePermissionCallback(requestCode, permissions, grantResults); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { | ||||
|     super.onActivityResult(requestCode, resultCode, data); | ||||
|     PermissionHelp.getInstance() | ||||
|         .handleSpecialPermissionCallback(getContext(), requestCode, resultCode, data); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,96 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.app.Dialog; | ||||
| import android.content.Context; | ||||
| import android.support.annotation.IdRes; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.view.View; | ||||
| import android.view.Window; | ||||
| 
 | ||||
| import com.arialyy.frame.module.AbsModule; | ||||
| import com.arialyy.frame.module.IOCProxy; | ||||
| import com.arialyy.frame.util.StringUtil; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2015/11/4. | ||||
|  * 继承Dialog | ||||
|  */ | ||||
| public abstract class AbsDialog extends Dialog { | ||||
|   protected String TAG = ""; | ||||
|   private Object mObj;    //被观察者
 | ||||
|   private IOCProxy mProxy; | ||||
|   private DialogSimpleModule mSimpleModule; | ||||
|   private ModuleFactory mModuleF; | ||||
| 
 | ||||
|   public AbsDialog(Context context) { | ||||
|     this(context, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * @param obj Dialog的寄主 | ||||
|    */ | ||||
|   public AbsDialog(Context context, Object obj) { | ||||
|     super(context); | ||||
|     mObj = obj; | ||||
|     requestWindowFeature(Window.FEATURE_NO_TITLE); | ||||
|     setContentView(setLayoutId()); | ||||
|     initDialog(); | ||||
|   } | ||||
| 
 | ||||
|   private void initDialog() { | ||||
|     TAG = StringUtil.getClassName(this); | ||||
|     mProxy = IOCProxy.newInstance(this); | ||||
|     mModuleF = ModuleFactory.newInstance(); | ||||
|     if (mObj != null) { | ||||
|       mSimpleModule = new DialogSimpleModule(getContext()); | ||||
|       IOCProxy.newInstance(mObj, mSimpleModule); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取简单打Moduel回调,这个一般用于回调数据给寄主 | ||||
|    */ | ||||
|   protected DialogSimpleModule getSimplerModule() { | ||||
|     if (mObj == null) { | ||||
|       throw new NullPointerException("必须设置寄主对象"); | ||||
|     } | ||||
|     return mSimpleModule; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(Class<M> clazz) { | ||||
|     M module = mModuleF.getModule(getContext(), clazz); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz Module class0 | ||||
|    * @param callback Module回调函数 | ||||
|    * @param <M> {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz, | ||||
|       @NonNull AbsModule.OnCallback callback) { | ||||
|     M module = mModuleF.getModule(getContext(), clazz); | ||||
|     module.setCallback(callback); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置资源布局 | ||||
|    */ | ||||
|   protected abstract int setLayoutId(); | ||||
| 
 | ||||
|   /** | ||||
|    * 数据回调 | ||||
|    */ | ||||
|   protected abstract void dataCallback(int result, Object obj); | ||||
| } | ||||
| @ -0,0 +1,160 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.app.Activity; | ||||
| import android.content.Intent; | ||||
| import android.databinding.DataBindingUtil; | ||||
| import android.databinding.ViewDataBinding; | ||||
| import android.os.Bundle; | ||||
| import android.support.annotation.IdRes; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v4.app.DialogFragment; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| 
 | ||||
| import com.arialyy.frame.module.AbsModule; | ||||
| import com.arialyy.frame.module.IOCProxy; | ||||
| import com.arialyy.frame.util.StringUtil; | ||||
| import com.lyy.frame.R; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2015/11/4. | ||||
|  * DialogFragment | ||||
|  */ | ||||
| public abstract class AbsDialogFragment<VB extends ViewDataBinding> extends DialogFragment { | ||||
|   protected String TAG = ""; | ||||
|   private VB mBind; | ||||
|   protected Object mObj; | ||||
|   protected View mRootView; | ||||
|   protected IOCProxy mProxy; | ||||
|   protected DialogSimpleModule mSimpleModule; | ||||
|   protected AbsActivity mActivity; | ||||
|   private ModuleFactory mModuleF; | ||||
| 
 | ||||
|   public AbsDialogFragment() { | ||||
|     this(null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * @param obj 被观察的对象 | ||||
|    */ | ||||
|   public AbsDialogFragment(Object obj) { | ||||
|     this(STYLE_NO_TITLE, R.style.MyDialog, obj); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * @param style DialogFragment.STYLE_NO_TITLE , STYLE_NO_FRAME; STYLE_NO_FRAME | STYLE_NO_TITLE | ||||
|    * @param theme Dialog风格 | ||||
|    * @param obj 被观察的对象 | ||||
|    */ | ||||
|   private AbsDialogFragment(int style, int theme, Object obj) { | ||||
|     setStyle(style, theme); | ||||
|     mObj = obj; | ||||
|   } | ||||
| 
 | ||||
|   @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, | ||||
|       @Nullable Bundle savedInstanceState) { | ||||
|     mBind = DataBindingUtil.inflate(inflater, setLayoutId(), container, false); | ||||
|     mRootView = mBind.getRoot(); | ||||
|     initFragment(); | ||||
|     return mRootView; | ||||
|   } | ||||
| 
 | ||||
|   public <V extends View> V findViewById(@IdRes int id) { | ||||
|     return mRootView.findViewById(id); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onAttach(Activity activity) { | ||||
|     super.onAttach(activity); | ||||
|     if (activity instanceof AbsActivity) { | ||||
|       mActivity = (AbsActivity) activity; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private void initFragment() { | ||||
|     TAG = StringUtil.getClassName(this); | ||||
|     mProxy = IOCProxy.newInstance(this); | ||||
|     mModuleF = ModuleFactory.newInstance(); | ||||
|     if (mObj != null) { | ||||
|       mSimpleModule = new DialogSimpleModule(getContext()); | ||||
|       IOCProxy.newInstance(mObj, mSimpleModule); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { | ||||
|     super.onActivityCreated(savedInstanceState); | ||||
|     init(savedInstanceState); | ||||
|   } | ||||
| 
 | ||||
|   protected abstract void init(Bundle savedInstanceState); | ||||
| 
 | ||||
|   /** | ||||
|    * 获取简单打Moduel回调,这个一般用于回调数据给寄主 | ||||
|    */ | ||||
|   protected DialogSimpleModule getSimplerModule() { | ||||
|     if (mObj == null) { | ||||
|       throw new NullPointerException("必须设置寄主对象"); | ||||
|     } | ||||
|     return mSimpleModule; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置资源布局 | ||||
|    */ | ||||
|   protected abstract int setLayoutId(); | ||||
| 
 | ||||
|   /** | ||||
|    * 获取binding对象 | ||||
|    */ | ||||
|   protected VB getBinding() { | ||||
|     return mBind; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(Class<M> clazz) { | ||||
|     M module = mModuleF.getModule(getContext(), clazz); | ||||
|     module.setHost(this); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz Module class0 | ||||
|    * @param callback Module回调函数 | ||||
|    * @param <M> {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz, | ||||
|       @NonNull AbsModule.OnCallback callback) { | ||||
|     M module = mModuleF.getModule(getContext(), clazz); | ||||
|     module.setCallback(callback); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 统一的回调接口 | ||||
|    * | ||||
|    * @param result 返回码,用来判断是哪个接口进行回调 | ||||
|    * @param data 回调数据 | ||||
|    */ | ||||
|   protected abstract void dataCallback(int result, Object data); | ||||
| 
 | ||||
|   @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, | ||||
|       @NonNull int[] grantResults) { | ||||
|     super.onRequestPermissionsResult(requestCode, permissions, grantResults); | ||||
|     PermissionHelp.getInstance().handlePermissionCallback(requestCode, permissions, grantResults); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { | ||||
|     super.onActivityResult(requestCode, resultCode, data); | ||||
|     PermissionHelp.getInstance() | ||||
|         .handleSpecialPermissionCallback(getContext(), requestCode, resultCode, data); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,274 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.databinding.DataBindingUtil; | ||||
| import android.databinding.ViewDataBinding; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v4.app.Fragment; | ||||
| import android.support.v4.app.FragmentContainer; | ||||
| import android.support.v4.view.ViewPager; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.FrameLayout; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.RelativeLayout; | ||||
| 
 | ||||
| import com.arialyy.frame.module.AbsModule; | ||||
| import com.arialyy.frame.module.IOCProxy; | ||||
| import com.arialyy.frame.temp.AbsTempView; | ||||
| import com.arialyy.frame.temp.OnTempBtClickListener; | ||||
| import com.arialyy.frame.temp.TempView; | ||||
| import com.arialyy.frame.util.ReflectionUtil; | ||||
| import com.arialyy.frame.util.StringUtil; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| 
 | ||||
| import java.lang.reflect.Field; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2015/11/4. | ||||
|  * 基础Fragment | ||||
|  */ | ||||
| public abstract class AbsFragment<VB extends ViewDataBinding> extends Fragment | ||||
|     implements OnTempBtClickListener { | ||||
|   protected String TAG = ""; | ||||
|   private VB mBind; | ||||
|   private IOCProxy mProxy; | ||||
|   protected View mRootView; | ||||
|   protected AbsActivity mActivity; | ||||
|   private ModuleFactory mModuleF; | ||||
|   protected boolean isInit; | ||||
|   protected AbsTempView mTempView; | ||||
|   protected boolean useTempView = true; | ||||
|   private ViewGroup mParent; | ||||
| 
 | ||||
|   @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, | ||||
|       Bundle savedInstanceState) { | ||||
|     mBind = DataBindingUtil.inflate(inflater, setLayoutId(), container, false); | ||||
|     initFragment(); | ||||
|     mRootView = mBind.getRoot(); | ||||
|     return mRootView; | ||||
|   } | ||||
| 
 | ||||
|   private void initFragment() { | ||||
|     TAG = StringUtil.getClassName(this); | ||||
|     mProxy = IOCProxy.newInstance(this); | ||||
|     mModuleF = ModuleFactory.newInstance(); | ||||
|     if (useTempView) { | ||||
|       mTempView = new TempView(getContext()); | ||||
|       mTempView.setBtListener(this); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onAttach(Context context) { | ||||
|     super.onAttach(context); | ||||
|     if (context instanceof AbsActivity) { | ||||
|       mActivity = (AbsActivity) context; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { | ||||
|     super.onActivityCreated(savedInstanceState); | ||||
|     Field field = ReflectionUtil.getField(getClass(), "mContainerId"); | ||||
|     Field containerField = ReflectionUtil.getField(getFragmentManager().getClass(), "mContainer"); | ||||
|     try { | ||||
|       int id = (int) field.get(this); | ||||
|       FragmentContainer container = (FragmentContainer) containerField.get(getFragmentManager()); | ||||
|       mParent = (ViewGroup) container.onFindViewById(id); | ||||
|     } catch (IllegalAccessException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     init(savedInstanceState); | ||||
|     isInit = true; | ||||
|     if (getUserVisibleHint()) { | ||||
|       onDelayLoad(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { | ||||
|     super.onViewCreated(view, savedInstanceState); | ||||
|     Field field = ReflectionUtil.getField(getClass(), "mContainer"); | ||||
|     try { | ||||
|       mParent = (ViewGroup) field.get(this); | ||||
|     } catch (IllegalAccessException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override public void setUserVisibleHint(boolean isVisibleToUser) { | ||||
|     super.setUserVisibleHint(isVisibleToUser); | ||||
|     if (isVisibleToUser && isInit) { | ||||
|       isInit = false; | ||||
|       onDelayLoad(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   protected abstract void init(Bundle savedInstanceState); | ||||
| 
 | ||||
|   /** | ||||
|    * 是否使用填充界面 | ||||
|    */ | ||||
|   protected void setUseTempView(boolean useTempView) { | ||||
|     this.useTempView = useTempView; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置自定义的TempView | ||||
|    */ | ||||
|   protected void setCustomTempView(AbsTempView tempView) { | ||||
|     mTempView = tempView; | ||||
|     mTempView.setBtListener(this); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 显示占位布局 | ||||
|    * | ||||
|    * @param type {@link TempView#ERROR} | ||||
|    * {@link TempView#DATA_NULL} | ||||
|    * {@link TempView#LOADING} | ||||
|    */ | ||||
|   protected void showTempView(int type) { | ||||
|     if (mTempView == null || !useTempView) { | ||||
|       return; | ||||
|     } | ||||
|     mTempView.setType(type); | ||||
|     if (mParent != null) { | ||||
|       int size = ViewGroup.LayoutParams.MATCH_PARENT; | ||||
|       ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(size, size); | ||||
|       if (mParent instanceof ViewPager) { | ||||
|         //                ViewPager vp = (ViewPager) mParent;
 | ||||
|         //                int position = vp.getCurrentItem();
 | ||||
|         //                View child = vp.getChildAt(position);
 | ||||
|         //                L.d(TAG, "hashcode ==> " + child.hashCode());
 | ||||
|         View child = mRootView; | ||||
|         if (child != null) { | ||||
|           if (child instanceof LinearLayout) { | ||||
|             LinearLayout ll = (LinearLayout) child; | ||||
|             ll.removeView(mTempView); | ||||
|             ll.addView(mTempView, 0, lp); | ||||
|           } else if (child instanceof RelativeLayout || child instanceof FrameLayout) { | ||||
|             ViewGroup vg = (ViewGroup) child; | ||||
|             vg.removeView(mTempView); | ||||
|             vg.addView(mTempView, lp); | ||||
|           } else { | ||||
|             L.e(TAG, "框架的填充只支持,LinearLayout、RelativeLayout、FrameLayout"); | ||||
|           } | ||||
|         } | ||||
|       } else { | ||||
|         mParent.removeView(mTempView); | ||||
|         mParent.addView(mTempView, lp); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 关闭占位布局 | ||||
|    */ | ||||
|   protected void hintTempView() { | ||||
|     hintTempView(0); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 延时关闭占位布局 | ||||
|    */ | ||||
|   protected void hintTempView(int delay) { | ||||
|     new Handler().postDelayed(new Runnable() { | ||||
|       @Override public void run() { | ||||
|         if (mTempView == null || !useTempView) { | ||||
|           return; | ||||
|         } | ||||
|         mTempView.clearFocus(); | ||||
|         if (mParent != null) { | ||||
|           if (mParent instanceof ViewPager) { | ||||
|             //                        ViewPager vp = (ViewPager) mParent;
 | ||||
|             //                        int position = vp.getCurrentItem();
 | ||||
|             //                        View child = vp.getChildAt(position);
 | ||||
|             View child = mRootView; | ||||
|             ViewGroup vg = (ViewGroup) child; | ||||
|             if (vg != null) { | ||||
|               vg.removeView(mTempView); | ||||
|             } | ||||
|           } else { | ||||
|             mParent.removeView(mTempView); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, delay); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onBtTempClick(View view, int type) { | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取填充View | ||||
|    */ | ||||
|   protected AbsTempView getTempView() { | ||||
|     return mTempView; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取binding对象 | ||||
|    */ | ||||
|   protected VB getBinding() { | ||||
|     return mBind; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz) { | ||||
|     M module = mModuleF.getModule(getContext(), clazz); | ||||
|     module.setHost(this); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz Module class0 | ||||
|    * @param callback Module回调函数 | ||||
|    * @param <M> {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz, | ||||
|       @NonNull AbsModule.OnCallback callback) { | ||||
|     M module = mModuleF.getModule(getContext(), clazz); | ||||
|     module.setCallback(callback); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 延时加载 | ||||
|    */ | ||||
|   protected abstract void onDelayLoad(); | ||||
| 
 | ||||
|   /** | ||||
|    * 设置资源布局 | ||||
|    */ | ||||
|   protected abstract int setLayoutId(); | ||||
| 
 | ||||
|   /** | ||||
|    * 数据回调 | ||||
|    */ | ||||
|   protected abstract void dataCallback(int result, Object obj); | ||||
| 
 | ||||
|   @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, | ||||
|       @NonNull int[] grantResults) { | ||||
|     super.onRequestPermissionsResult(requestCode, permissions, grantResults); | ||||
|     PermissionHelp.getInstance().handlePermissionCallback(requestCode, permissions, grantResults); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { | ||||
|     super.onActivityResult(requestCode, resultCode, data); | ||||
|     PermissionHelp.getInstance() | ||||
|         .handleSpecialPermissionCallback(getContext(), requestCode, resultCode, data); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,203 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.app.ActivityManager; | ||||
| import android.content.Context; | ||||
| import android.os.Process; | ||||
| import com.arialyy.frame.util.show.FL; | ||||
| import java.io.File; | ||||
| import java.util.Iterator; | ||||
| import java.util.Stack; | ||||
| 
 | ||||
| /** | ||||
|  * Created by “AriaLyy@outlook.com” on 2015/11/4. | ||||
|  * APP生命周期管理类管理 | ||||
|  */ | ||||
| public class AbsFrame { | ||||
|   private static final String TAG = "AbsFrame"; | ||||
|   private static final Object LOCK = new Object(); | ||||
|   private volatile static AbsFrame mManager = null; | ||||
|   private Context mContext; | ||||
|   private Stack<AbsActivity> mActivityStack = new Stack<>(); | ||||
| 
 | ||||
|   private AbsFrame() { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   private AbsFrame(Context context) { | ||||
|     mContext = context; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 初始化框架 | ||||
|    */ | ||||
|   public static AbsFrame init(Context applicationContext) { | ||||
|     if (mManager == null) { | ||||
|       synchronized (LOCK) { | ||||
|         if (mManager == null) { | ||||
|           mManager = new AbsFrame(applicationContext); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return mManager; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取AppManager管流程实例 | ||||
|    */ | ||||
|   public static AbsFrame getInstance() { | ||||
|     if (mManager == null) { | ||||
|       throw new NullPointerException("请在application 的 onCreate 方法里面使用MVVMFrame.init()方法进行初始化操作"); | ||||
|     } | ||||
|     return mManager; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * activity 是否存在 | ||||
|    */ | ||||
|   public boolean activityExists(Class clazz) { | ||||
|     for (AbsActivity activity : mActivityStack) { | ||||
|       if (activity.getClass().getName().equals(clazz.getName())) { | ||||
|         return true; | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Activity栈 | ||||
|    */ | ||||
|   public Stack<AbsActivity> getActivityStack() { | ||||
|     return mActivityStack; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 开启异常捕获 | ||||
|    * 日志文件位于/data/data/Package Name/cache//crash/2016.10.26_AbsExceptionFile.crash
 | ||||
|    */ | ||||
|   public void openCrashHandler() { | ||||
|     openCrashHandler("", ""); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 开启异常捕获 | ||||
|    * 需要网络权限,get请求,异常参数,需要下面两个网络权限 | ||||
|    * android:name="android.permission.INTERNET" | ||||
|    * android:name="android.permission.ACCESS_NETWORK_STATE" | ||||
|    * | ||||
|    * @param serverHost 服务器地址 | ||||
|    * @param key 数据传输键值 | ||||
|    */ | ||||
|   public AbsFrame openCrashHandler(String serverHost, String key) { | ||||
|     CrashHandler handler = CrashHandler.getInstance(mContext); | ||||
|     handler.setServerHost(serverHost, key); | ||||
|     Thread.setDefaultUncaughtExceptionHandler(handler); | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 堆栈大小 | ||||
|    */ | ||||
|   public int getActivitySize() { | ||||
|     return mActivityStack.size(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取指定的Activity | ||||
|    */ | ||||
|   public AbsActivity getActivity(int location) { | ||||
|     return mActivityStack.get(location); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 添加Activity到堆栈 | ||||
|    */ | ||||
|   public void addActivity(AbsActivity activity) { | ||||
|     if (mActivityStack == null) { | ||||
|       mActivityStack = new Stack<>(); | ||||
|     } | ||||
|     mActivityStack.add(activity); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取当前Activity(堆栈中最后一个压入的) | ||||
|    */ | ||||
|   public AbsActivity getCurrentActivity() { | ||||
|     return mActivityStack.lastElement(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 结束当前Activity(堆栈中最后一个压入的) | ||||
|    */ | ||||
|   public void finishActivity() { | ||||
|     finishActivity(mActivityStack.lastElement()); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 结束指定的Activity | ||||
|    */ | ||||
|   public void finishActivity(AbsActivity activity) { | ||||
|     if (activity != null) { | ||||
|       activity.finish(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 移除指定的Activity | ||||
|    */ | ||||
|   public void removeActivity(AbsActivity activity) { | ||||
|     if (activity != null) { | ||||
|       int i = mActivityStack.search(activity); | ||||
|       if (i != -1) { | ||||
|         mActivityStack.remove(activity); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 结束指定类名的Activity | ||||
|    */ | ||||
|   public void finishActivity(Class<?> cls) { | ||||
|     Iterator<AbsActivity> iter = mActivityStack.iterator(); | ||||
|     while (iter.hasNext()) { | ||||
|       AbsActivity activity = iter.next(); | ||||
|       if (activity.getClass().getName().equals(cls.getName())) { | ||||
|         iter.remove(); | ||||
|         activity.finish(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 结束所有Activity | ||||
|    */ | ||||
|   public void finishAllActivity() { | ||||
|     for (int i = 0, size = mActivityStack.size(); i < size; i++) { | ||||
|       if (mActivityStack.get(i) != null && mActivityStack.size() > 0) { | ||||
|         mActivityStack.get(i).finish(); | ||||
|       } | ||||
|     } | ||||
|     mActivityStack.clear(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 退出应用程序 | ||||
|    * | ||||
|    * @param isBackground 是否开开启后台运行 | ||||
|    */ | ||||
|   public void exitApp(Boolean isBackground) { | ||||
|     try { | ||||
|       finishAllActivity(); | ||||
|       //ActivityManager activityMgr =
 | ||||
|       //    (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
 | ||||
|       //activityMgr.restartPackage(mContext.getPackageName());
 | ||||
|     } catch (Exception e) { | ||||
|       FL.e(TAG, FL.getExceptionString(e)); | ||||
|     } finally { | ||||
|       // 注意,如果您有后台程序运行,请不要支持此句子
 | ||||
|       if (!isBackground) { | ||||
|         System.exit(0); | ||||
|         //Process.killProcess(Process.myPid());
 | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,133 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.graphics.Color; | ||||
| import android.graphics.drawable.ColorDrawable; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.PopupWindow; | ||||
| 
 | ||||
| import com.arialyy.frame.module.AbsModule; | ||||
| import com.arialyy.frame.module.IOCProxy; | ||||
| import com.arialyy.frame.util.StringUtil; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2015/12/3. | ||||
|  * 抽象的Popupwindow悬浮框 | ||||
|  */ | ||||
| public abstract class AbsPopupWindow extends PopupWindow { | ||||
| 
 | ||||
|   protected String TAG; | ||||
|   private static Context mContext; | ||||
|   private Drawable mBackground; | ||||
|   protected View mView; | ||||
|   private Object mObj; | ||||
|   protected IOCProxy mProxy; | ||||
|   protected DialogSimpleModule mSimpleModule; | ||||
|   private ModuleFactory mModuleF; | ||||
| 
 | ||||
|   public AbsPopupWindow(Context context) { | ||||
|     this(context, null); | ||||
|   } | ||||
| 
 | ||||
|   public AbsPopupWindow(Context context, Drawable background) { | ||||
|     this(context, background, null); | ||||
|   } | ||||
| 
 | ||||
|   public AbsPopupWindow(Context context, Drawable background, Object obj) { | ||||
|     mContext = context; | ||||
|     mBackground = background; | ||||
|     initPopupWindow(); | ||||
|     mProxy = IOCProxy.newInstance(this); | ||||
|     if (obj != null) { | ||||
|       mObj = obj; | ||||
|       mSimpleModule = new DialogSimpleModule(getContext()); | ||||
|       IOCProxy.newInstance(mObj, mSimpleModule); | ||||
|     } | ||||
|     mModuleF = ModuleFactory.newInstance(); | ||||
|     init(); | ||||
|   } | ||||
| 
 | ||||
|   protected void init() { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   private void initPopupWindow() { | ||||
|     mView = LayoutInflater.from(mContext).inflate(setLayoutId(), null); | ||||
|     setContentView(mView); | ||||
|     TAG = StringUtil.getClassName(this); | ||||
|     // 设置SelectPicPopupWindow弹出窗体的宽
 | ||||
|     setWidth(ViewGroup.LayoutParams.MATCH_PARENT); | ||||
|     // 设置SelectPicPopupWindow弹出窗体的高
 | ||||
|     setHeight(ViewGroup.LayoutParams.MATCH_PARENT); | ||||
|     setFocusable(true); | ||||
|     // 设置SelectPicPopupWindow弹出窗体动画效果
 | ||||
|     //        setAnimationStyle(R.style.wisdom_anim_style);
 | ||||
|     // 实例化一个ColorDrawable颜色为半透明
 | ||||
|     if (mBackground == null) { | ||||
|       mBackground = new ColorDrawable(Color.parseColor("#7f000000")); | ||||
|     } | ||||
|     // 设置SelectPicPopupWindow弹出窗体的背景
 | ||||
|     setBackgroundDrawable(mBackground); | ||||
|   } | ||||
| 
 | ||||
|   protected <T extends View> T getViewWithTag(Object tag) { | ||||
|     T result = (T) mView.findViewWithTag(tag); | ||||
|     if (result == null) throw new NullPointerException("没有找到tag为【" + tag + "】的控件"); | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(Class<M> clazz) { | ||||
|     M module = mModuleF.getModule(getContext(), clazz); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    * | ||||
|    * @param clazz Module class0 | ||||
|    * @param callback Module回调函数 | ||||
|    * @param <M> {@link AbsModule} | ||||
|    */ | ||||
|   protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz, | ||||
|       @NonNull AbsModule.OnCallback callback) { | ||||
|     M module = mModuleF.getModule(getContext(), clazz); | ||||
|     module.setCallback(callback); | ||||
|     mProxy.changeModule(module); | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取简单打Moduel回调,这个一般用于回调数据给寄主 | ||||
|    */ | ||||
|   protected DialogSimpleModule getSimplerModule() { | ||||
|     if (mObj == null) { | ||||
|       throw new NullPointerException("必须设置寄主对象"); | ||||
|     } | ||||
|     return mSimpleModule; | ||||
|   } | ||||
| 
 | ||||
|   public Context getContext() { | ||||
|     return mContext; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置资源布局 | ||||
|    */ | ||||
|   protected abstract int setLayoutId(); | ||||
| 
 | ||||
|   /** | ||||
|    * 数据回调 | ||||
|    */ | ||||
|   protected abstract void dataCallback(int result, Object obj); | ||||
| } | ||||
| @ -0,0 +1,60 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| 
 | ||||
| import android.databinding.ViewDataBinding; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/9/16. | ||||
|  * Binding工厂 | ||||
|  */ | ||||
| public class BindingFactory { | ||||
|   private final String TAG = "BindingFactory"; | ||||
| 
 | ||||
|   private Map<Integer, ViewDataBinding> mBindings = new ConcurrentHashMap<>(); | ||||
| 
 | ||||
|   private BindingFactory() { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 需要保证每个对象都有独立的享元工厂 | ||||
|    */ | ||||
|   public static BindingFactory newInstance() { | ||||
|     return new BindingFactory(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Binding | ||||
|    * | ||||
|    * @param obj Module寄主 | ||||
|    */ | ||||
|   public <VB extends ViewDataBinding> VB getBinding(Object obj, Class<VB> clazz) { | ||||
|     VB vb = (VB) mBindings.get(clazz.hashCode()); | ||||
|     if (vb == null) { | ||||
|       vb = loadBind(obj, clazz); | ||||
|     } | ||||
|     return vb; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从其它组件中加载binding | ||||
|    * | ||||
|    * @param obj Module寄主 | ||||
|    * @param clazz 具体的Binding | ||||
|    * @param <VB> ViewDataBinding | ||||
|    */ | ||||
|   private <VB extends ViewDataBinding> VB loadBind(Object obj, Class<VB> clazz) { | ||||
|     VB vb = null; | ||||
|     if (obj instanceof AbsActivity) { | ||||
|       vb = (VB) ((AbsActivity) obj).getBinding(); | ||||
|     } else if (obj instanceof AbsFragment) { | ||||
|       vb = (VB) ((AbsFragment) obj).getBinding(); | ||||
|     } else if (obj instanceof AbsDialogFragment) { | ||||
|       vb = (VB) ((AbsDialogFragment) obj).getBinding(); | ||||
|     } | ||||
|     mBindings.put(clazz.hashCode(), vb); | ||||
|     return vb; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,167 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.Manifest; | ||||
| import android.content.Context; | ||||
| import android.os.Build; | ||||
| import android.os.Looper; | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| import com.arialyy.frame.http.HttpUtil; | ||||
| import com.arialyy.frame.util.AndroidUtils; | ||||
| import com.arialyy.frame.util.CalendarUtils; | ||||
| import com.arialyy.frame.util.FileUtil; | ||||
| import com.arialyy.frame.util.NetUtils; | ||||
| import com.arialyy.frame.util.show.FL; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| import com.arialyy.frame.util.show.T; | ||||
| import com.google.gson.Gson; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.FileWriter; | ||||
| import java.io.PrintWriter; | ||||
| import java.util.Map; | ||||
| import java.util.WeakHashMap; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/4/21. | ||||
|  * 异常捕获 | ||||
|  */ | ||||
| final class CrashHandler implements Thread.UncaughtExceptionHandler { | ||||
|   private static final Object LOCK = new Object(); | ||||
|   private static volatile CrashHandler INSTANCE = null; | ||||
|   private static final String TAG = "CrashHandler"; | ||||
|   private Thread.UncaughtExceptionHandler mDefaultHandler; | ||||
|   private Context mContext; | ||||
|   private String mServerHost, mPramKey; | ||||
|   private String mExceptionFileName = "AbsExceptionFile.crash"; | ||||
| 
 | ||||
|   /** | ||||
|    * 获取CrashHandler实例 ,单例模式 | ||||
|    */ | ||||
|   public static CrashHandler getInstance(Context context) { | ||||
|     if (INSTANCE == null) { | ||||
|       synchronized (LOCK) { | ||||
|         INSTANCE = new CrashHandler(context); | ||||
|       } | ||||
|     } | ||||
|     return INSTANCE; | ||||
|   } | ||||
| 
 | ||||
|   private CrashHandler(Context context) { | ||||
|     mContext = context; | ||||
|     mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 开启异常捕获 | ||||
|    * 需要网络权限,get请求,异常参数 | ||||
|    * | ||||
|    * @param serverHost 服务器地址 | ||||
|    * @param key 数据传输键值 | ||||
|    */ | ||||
|   public void setServerHost(String serverHost, String key) { | ||||
|     mServerHost = serverHost; | ||||
|     mPramKey = key; | ||||
|   } | ||||
| 
 | ||||
|   @Override public void uncaughtException(Thread thread, Throwable ex) { | ||||
|     if (!handleException(ex) && mDefaultHandler != null) { | ||||
|       mDefaultHandler.uncaughtException(thread, ex); | ||||
|     } else { | ||||
|       // Sleep一会后结束程序
 | ||||
|       try { | ||||
|         Thread.sleep(2000); | ||||
|       } catch (InterruptedException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|       //不要把线程都杀了,否则连日志都看不了
 | ||||
|       //            android.os.Process.killProcess(android.os.Process.myPid());
 | ||||
|       //如果把这句话注释掉,有异常都不会退出
 | ||||
|       System.exit(10); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 处理捕获到的异常 | ||||
|    */ | ||||
|   private boolean handleException(Throwable ex) { | ||||
|     if (ex == null) { | ||||
|       return false; | ||||
|     } | ||||
|     //在这里处理崩溃逻辑,将不再显示FC对话框
 | ||||
|     new Thread() { | ||||
|       @Override public void run() { | ||||
|         Looper.prepare(); | ||||
|         T.showLong(mContext, "很抱歉,程序出现异常,即将退出"); | ||||
|         Looper.loop(); | ||||
|       } | ||||
|     }.start(); | ||||
|     sendExceptionInfo(ex); | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 发送异常数据给服务器 | ||||
|    */ | ||||
|   private void sendExceptionInfo(final Throwable ex) { | ||||
|     ExceptionInfo info = new ExceptionInfo(); | ||||
|     info.time = CalendarUtils.getNowDataTime(); | ||||
|     info.versionCode = AndroidUtils.getVersionCode(mContext); | ||||
|     info.versionName = AndroidUtils.getVersionName(mContext); | ||||
|     info.systemVersionCode = Build.VERSION.SDK_INT; | ||||
|     info.phoneModel = Build.MODEL; | ||||
|     info.exceptionMsg = FL.getExceptionString(ex); | ||||
|     if (AndroidUtils.checkPermission(mContext, Manifest.permission.INTERNET) | ||||
|         && AndroidUtils.checkPermission(mContext, Manifest.permission.ACCESS_NETWORK_STATE)) { | ||||
|       if (NetUtils.isConnected(mContext) && !TextUtils.isEmpty(mServerHost) && !TextUtils.isEmpty( | ||||
|           mPramKey)) { | ||||
|         String objStr = new Gson().toJson(info); | ||||
|         HttpUtil util = HttpUtil.getInstance(mContext); | ||||
|         Map<String, String> params = new WeakHashMap<>(); | ||||
|         params.put(mPramKey, objStr); | ||||
|         util.get(mServerHost, params, new HttpUtil.AbsResponse()); | ||||
|       } | ||||
|     } else { | ||||
|       L.e(TAG, | ||||
|           "请在manifest文件定义android.permission.INTERNET和android.permission.ACCESS_NETWORK_STATE权限"); | ||||
|       return; | ||||
|     } | ||||
|     File file = new File(mContext.getCacheDir().getPath() + "/crash/" + mExceptionFileName); | ||||
|     if (!file.exists()) { | ||||
|       FileUtil.createFile(file.getPath()); | ||||
|     } | ||||
|     writeExceptionToFile(info.exceptionMsg, file); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 将异常日志写入文件 | ||||
|    */ | ||||
|   private void writeExceptionToFile(String message, File crashFile) { | ||||
|     StringBuffer stringBuffer = new StringBuffer(); | ||||
|     stringBuffer.append(CalendarUtils.getNowDataTime()); | ||||
|     stringBuffer.append("\n"); | ||||
|     stringBuffer.append(message); | ||||
|     stringBuffer.append("\n"); | ||||
|     PrintWriter writer = null; | ||||
|     try { | ||||
|       writer = new PrintWriter(new FileWriter(crashFile, true)); | ||||
|       writer.append(stringBuffer); | ||||
|       writer.flush(); | ||||
|     } catch (Exception e) { | ||||
|       e.printStackTrace(); | ||||
|     } finally { | ||||
|       if (writer != null) { | ||||
|         writer.close(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private class ExceptionInfo { | ||||
|     int versionCode; | ||||
|     String versionName; | ||||
|     int systemVersionCode; | ||||
|     String exceptionMsg; | ||||
|     String phoneModel; | ||||
|     String time; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.os.Bundle; | ||||
| 
 | ||||
| import com.arialyy.frame.module.AbsModule; | ||||
| 
 | ||||
| /** | ||||
|  * Created by AriaLyy on 2015/2/9. | ||||
|  * 框架提供的默认的对话框的Module | ||||
|  */ | ||||
| public class DialogSimpleModule extends AbsModule { | ||||
| 
 | ||||
|   public DialogSimpleModule(Context context) { | ||||
|     super(context); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 统一的回调 | ||||
|    */ | ||||
|   public void onDialog(int result, Object data) { | ||||
|     callback(result, data); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 可设置参数和回调名的回调函数 | ||||
|    */ | ||||
|   @Deprecated public void onDialog(String methodName, Class<?> param, Object data) { | ||||
|     callback(methodName, param, data); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Dialog的默认回调 | ||||
|    * | ||||
|    * @param b 需要回调的数据 | ||||
|    */ | ||||
|   @Deprecated public void onDialog(Bundle b) { | ||||
|     callback("onDialog", Bundle.class, b); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,68 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| 
 | ||||
| import com.arialyy.frame.module.AbsModule; | ||||
| 
 | ||||
| import java.lang.reflect.Constructor; | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2015/8/31. | ||||
|  * Module共享工厂 | ||||
|  */ | ||||
| public class ModuleFactory { | ||||
| 
 | ||||
|   private final String TAG = "ModuleFactory"; | ||||
| 
 | ||||
|   private Map<Integer, AbsModule> mModules = new ConcurrentHashMap<>(); | ||||
| 
 | ||||
|   private ModuleFactory() { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 需要保证每个对象都有独立的享元工厂 | ||||
|    */ | ||||
|   public static ModuleFactory newInstance() { | ||||
|     return new ModuleFactory(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Module | ||||
|    */ | ||||
|   public <M extends AbsModule> M getModule(Context context, Class<M> clazz) { | ||||
|     M module = (M) mModules.get(clazz.hashCode()); | ||||
|     if (module == null) { | ||||
|       return newInstanceModule(context, clazz); | ||||
|     } | ||||
|     return module; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 构造一个新的Module | ||||
|    */ | ||||
|   private <T extends AbsModule> T newInstanceModule(Context context, Class<T> clazz) { | ||||
|     Class[] paramTypes = { Context.class }; | ||||
|     Object[] params = { context }; | ||||
|     try { | ||||
|       Constructor<T> con = clazz.getConstructor(paramTypes); | ||||
|       con.setAccessible(true); | ||||
|       T module = con.newInstance(params); | ||||
|       mModules.put(clazz.hashCode(), module); | ||||
|       return module; | ||||
|     } catch (NoSuchMethodException e) { | ||||
|       e.printStackTrace(); | ||||
|     } catch (InvocationTargetException e) { | ||||
|       e.printStackTrace(); | ||||
|     } catch (InstantiationException e) { | ||||
|       e.printStackTrace(); | ||||
|     } catch (IllegalAccessException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,81 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.util.SparseArray; | ||||
| 
 | ||||
| import com.arialyy.frame.util.ReflectionUtil; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/4/5. | ||||
|  * 更新帮助类 | ||||
|  */ | ||||
| public class NotifyHelp { | ||||
|   private static volatile NotifyHelp INSTANCE = null; | ||||
|   private static final Object LOCK = new Object(); | ||||
|   private SparseArray<SparseArray<OnNotifyCallback>> mNotifyObjs = new SparseArray<>(); | ||||
| 
 | ||||
|   public interface OnNotifyCallback { | ||||
|     public void onNotify(int action, Object obj); | ||||
|   } | ||||
| 
 | ||||
|   public static NotifyHelp getInstance() { | ||||
|     if (INSTANCE == null) { | ||||
|       synchronized (LOCK) { | ||||
|         INSTANCE = new NotifyHelp(); | ||||
|       } | ||||
|     } | ||||
|     return INSTANCE; | ||||
|   } | ||||
| 
 | ||||
|   private NotifyHelp() { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   public void addObj(int flag, OnNotifyCallback callback) { | ||||
|     SparseArray<OnNotifyCallback> array = mNotifyObjs.get(flag); | ||||
|     if (array == null) { | ||||
|       array = new SparseArray<>(); | ||||
|     } | ||||
|     array.put(callback.hashCode(), callback); | ||||
|     mNotifyObjs.put(flag, array); | ||||
|   } | ||||
| 
 | ||||
|   public void removeObj(int flag) { | ||||
|     mNotifyObjs.delete(flag); | ||||
|   } | ||||
| 
 | ||||
|   public void clear() { | ||||
|     mNotifyObjs.clear(); | ||||
|   } | ||||
| 
 | ||||
|   public void update(int flag) { | ||||
|     update(flag, -1, null); | ||||
|   } | ||||
| 
 | ||||
|   public void update(int flag, int action) { | ||||
|     update(flag, action, null); | ||||
|   } | ||||
| 
 | ||||
|   public void update(int flag, int action, Object obj) { | ||||
|     if (mNotifyObjs == null || mNotifyObjs.size() == 0) { | ||||
|       return; | ||||
|     } | ||||
|     SparseArray<OnNotifyCallback> array = mNotifyObjs.get(flag); | ||||
|     if (array == null || array.size() == 0) { | ||||
|       return; | ||||
|     } | ||||
|     try { | ||||
|       int[] keys = (int[]) ReflectionUtil.getField(SparseArray.class, "mKeys").get(array); | ||||
|       for (int key : keys) { | ||||
|         if (key == 0) { | ||||
|           continue; | ||||
|         } | ||||
|         OnNotifyCallback callback = array.get(key); | ||||
|         if (callback != null) { | ||||
|           callback.onNotify(action, obj); | ||||
|         } | ||||
|       } | ||||
|     } catch (IllegalAccessException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,70 @@ | ||||
| package com.arialyy.frame.core; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.provider.Settings; | ||||
| import android.support.annotation.NonNull; | ||||
| 
 | ||||
| import com.arialyy.frame.permission.OnPermissionCallback; | ||||
| import com.arialyy.frame.permission.PermissionManager; | ||||
| import com.arialyy.frame.util.AndroidVersionUtil; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/4/12. | ||||
|  * 权限回调帮助类 | ||||
|  */ | ||||
| class PermissionHelp { | ||||
|   public static final Object LOCK = new Object(); | ||||
|   public volatile static PermissionHelp INSTANCE = null; | ||||
|   public PermissionManager mPm; | ||||
| 
 | ||||
|   public static PermissionHelp getInstance() { | ||||
|     if (INSTANCE == null) { | ||||
|       synchronized (LOCK) { | ||||
|         INSTANCE = new PermissionHelp(); | ||||
|       } | ||||
|     } | ||||
|     return INSTANCE; | ||||
|   } | ||||
| 
 | ||||
|   private PermissionHelp() { | ||||
|     mPm = PermissionManager.getInstance(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 处理权限申请回调 | ||||
|    */ | ||||
|   public void handlePermissionCallback(int requestCode, @NonNull String[] permissions, | ||||
|       @NonNull int[] grantResults) { | ||||
|     for (int state : grantResults) { | ||||
|       if (state == PackageManager.PERMISSION_GRANTED) { | ||||
|         mPm.onSuccess(permissions); | ||||
|       } else { | ||||
|         mPm.onFail(permissions); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 处理特殊权限申请,如悬浮框,系统设置修改等特殊权限 | ||||
|    */ | ||||
|   public void handleSpecialPermissionCallback(Context context, int requestCode, int resultCode, | ||||
|       Intent data) { | ||||
|     if (AndroidVersionUtil.hasM()) { | ||||
|       if (requestCode == OnPermissionCallback.PERMISSION_ALERT_WINDOW) { | ||||
|         if (Settings.canDrawOverlays(context)) {       //在这判断是否请求权限成功
 | ||||
|           mPm.onSuccess(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); | ||||
|         } else { | ||||
|           mPm.onFail(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); | ||||
|         } | ||||
|       } else if (requestCode == OnPermissionCallback.PERMISSION_WRITE_SETTING) { | ||||
|         if (Settings.System.canWrite(context)) { | ||||
|           mPm.onSuccess(Settings.ACTION_MANAGE_WRITE_SETTINGS); | ||||
|         } else { | ||||
|           mPm.onFail(Settings.ACTION_MANAGE_WRITE_SETTINGS); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,339 @@ | ||||
| package com.arialyy.frame.http; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.os.Handler; | ||||
| import android.os.Looper; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| import com.arialyy.frame.cache.CacheUtil; | ||||
| import com.arialyy.frame.http.inf.IResponse; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| 
 | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.BufferedReader; | ||||
| import java.io.DataOutputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
| import java.net.HttpURLConnection; | ||||
| import java.net.MalformedURLException; | ||||
| import java.net.URL; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import java.util.UUID; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| 
 | ||||
| import okhttp3.Call; | ||||
| import okhttp3.Callback; | ||||
| import okhttp3.FormBody; | ||||
| import okhttp3.Headers; | ||||
| import okhttp3.OkHttpClient; | ||||
| import okhttp3.Request; | ||||
| import okhttp3.RequestBody; | ||||
| import okhttp3.Response; | ||||
| 
 | ||||
| /** | ||||
|  * Created by “AriaLyy@outlook.com” on 2015/11/5. | ||||
|  * 网络连接工具 | ||||
|  */ | ||||
| public class HttpUtil { | ||||
|   private static final String TAG = "HttpUtil"; | ||||
|   private Context mContext = null; | ||||
|   private static volatile HttpUtil mUtil = null; | ||||
|   private static final Object LOCK = new Object(); | ||||
|   private CacheUtil mCacheUtil; | ||||
|   private Handler mHandler; | ||||
|   private static final int TIME_OUT = 5000; | ||||
|   public static final String CONTENT_TYPE_IMG = "image/*"; | ||||
|   public static final String CONTENT_TYPE_TEXT = "text/*"; | ||||
|   public static final String CONTENT_TYPE_FILE = "application/octet-stream"; | ||||
| 
 | ||||
|   private HttpUtil() { | ||||
|   } | ||||
| 
 | ||||
|   private HttpUtil(Context context) { | ||||
|     mContext = context; | ||||
|     mCacheUtil = new CacheUtil.Builder(context).openDiskCache().build(); | ||||
|     mHandler = new Handler(Looper.getMainLooper()); | ||||
|   } | ||||
| 
 | ||||
|   public static HttpUtil getInstance(Context context) { | ||||
|     if (mUtil == null) { | ||||
|       synchronized (LOCK) { | ||||
|         if (mUtil == null) { | ||||
|           mUtil = new HttpUtil(context); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return mUtil; | ||||
|   } | ||||
| 
 | ||||
|   public void get(final @NonNull String url, @NonNull final IResponse absResponse) { | ||||
|     get(url, null, absResponse, false); | ||||
|   } | ||||
| 
 | ||||
|   public void get(final @NonNull String url, @NonNull final IResponse absResponse, | ||||
|       boolean useCache) { | ||||
|     get(url, null, absResponse, useCache); | ||||
|   } | ||||
| 
 | ||||
|   public void get(final @NonNull String url, final Map<String, String> params, | ||||
|       @NonNull final IResponse absResponse) { | ||||
|     get(url, params, absResponse, false); | ||||
|   } | ||||
| 
 | ||||
|   public void post(final @NonNull String url, @NonNull final IResponse absResponse) { | ||||
|     post(url, null, null, absResponse, false); | ||||
|   } | ||||
| 
 | ||||
|   public void post(final @NonNull String url, final Map<String, String> params, | ||||
|       @NonNull final IResponse absResponse) { | ||||
|     post(url, params, null, absResponse, false); | ||||
|   } | ||||
| 
 | ||||
|   public void post(final @NonNull String url, final Map<String, String> params, | ||||
|       @NonNull final IResponse absResponse, final boolean useCache) { | ||||
|     post(url, params, null, absResponse, useCache); | ||||
|   } | ||||
| 
 | ||||
|   public void post(final @NonNull String url, final Map<String, String> params, | ||||
|       final Map<String, String> header, @NonNull final IResponse absResponse) { | ||||
|     post(url, params, header, absResponse, false); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 上传文件 | ||||
|    * | ||||
|    * @param key 上传文件键值 | ||||
|    */ | ||||
|   public void uploadFile(@NonNull final String url, @NonNull final String filePath, | ||||
|       @NonNull final String key, final String contentType, final Map<String, String> header, | ||||
|       @NonNull final IResponse absResponse) { | ||||
|     new Thread(new Runnable() { | ||||
|       @Override public void run() { | ||||
|         File file = new File(filePath); | ||||
|         String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成
 | ||||
|         String PREFIX = "--", LINE_END = "\r\n"; | ||||
|         String CONTENT_TYPE = "multipart/form-data"; // 内容类型
 | ||||
|         try { | ||||
|           HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); | ||||
|           conn.setReadTimeout(5000); | ||||
|           conn.setConnectTimeout(5000); | ||||
|           conn.setDoInput(true); | ||||
|           conn.setDoOutput(true); | ||||
|           conn.setUseCaches(false); | ||||
|           conn.setRequestMethod("POST"); | ||||
|           conn.setRequestProperty("Charset", "utf-8"); // 设置编码
 | ||||
|           conn.setRequestProperty("connection", "keep-alive"); | ||||
|           conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY); | ||||
| 
 | ||||
|           if (header != null && header.size() > 0) { | ||||
|             Set<String> keys = header.keySet(); | ||||
|             for (String key : keys) { | ||||
|               conn.setRequestProperty(key, header.get(key)); | ||||
|             } | ||||
|           } | ||||
|           OutputStream outputSteam = conn.getOutputStream(); | ||||
|           DataOutputStream dos = new DataOutputStream(outputSteam); | ||||
|           StringBuilder sb = new StringBuilder(); | ||||
|           sb.append(PREFIX); | ||||
|           sb.append(BOUNDARY); | ||||
|           sb.append(LINE_END); | ||||
|           sb.append("Content-Disposition: form-data; name=\"") | ||||
|               .append(key) | ||||
|               .append("\"; filename=\"") | ||||
|               .append(file.getName()) | ||||
|               .append("\"") | ||||
|               .append(LINE_END); | ||||
|           sb.append("Content-Type:").append(contentType).append("; charset=utf-8").append(LINE_END); | ||||
|           sb.append(LINE_END); | ||||
|           dos.write(sb.toString().getBytes()); | ||||
|           InputStream is = new FileInputStream(file); | ||||
|           byte[] bytes = new byte[1024]; | ||||
|           int len = 0; | ||||
|           while ((len = is.read(bytes)) != -1) { | ||||
|             dos.write(bytes, 0, len); | ||||
|           } | ||||
|           is.close(); | ||||
|           dos.write(LINE_END.getBytes()); | ||||
|           byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes(); | ||||
|           dos.write(end_data); | ||||
|           dos.flush(); | ||||
|           int res = conn.getResponseCode(); | ||||
|           if (res == 200) { | ||||
|             BufferedInputStream inputStream = new BufferedInputStream(conn.getInputStream()); | ||||
|             byte[] buf = new byte[1024]; | ||||
|             StringBuilder stringBuilder = new StringBuilder(); | ||||
|             while (inputStream.read(buf) > 0) { | ||||
|               stringBuilder.append(new String(buf, 0, buf.length)); | ||||
|             } | ||||
|             String data = stringBuilder.toString(); | ||||
|             L.j(data); | ||||
|             absResponse.onResponse(data); | ||||
|           } else { | ||||
|             absResponse.onError("error"); | ||||
|           } | ||||
|         } catch (MalformedURLException e) { | ||||
|           e.printStackTrace(); | ||||
|         } catch (IOException e) { | ||||
|           e.printStackTrace(); | ||||
|         } | ||||
|       } | ||||
|     }).start(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 基本get方法 | ||||
|    */ | ||||
|   public void get(final @NonNull String url, final Map<String, String> params, | ||||
|       @NonNull final IResponse absResponse, final boolean useCache) { | ||||
|     L.v(TAG, "请求链接 >>>> " + url); | ||||
|     String requestUrl = url; | ||||
|     if (params != null && params.size() > 0) { | ||||
|       Set<String> keys = params.keySet(); | ||||
|       int i = 0; | ||||
|       requestUrl += "?"; | ||||
|       for (String key : keys) { | ||||
|         i++; | ||||
|         requestUrl += key + "=" + params.get(key) + (i < params.size() ? "&" : ""); | ||||
|       } | ||||
|       L.v(TAG, "请求参数为 >>>> "); | ||||
|       L.m(params); | ||||
|     } | ||||
| 
 | ||||
|     OkHttpClient client = new OkHttpClient.Builder().connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS) | ||||
|         .writeTimeout(TIME_OUT, TimeUnit.MILLISECONDS) | ||||
|         .readTimeout(300000, TimeUnit.MILLISECONDS) | ||||
|         .build(); | ||||
|     final Request request = new Request.Builder().url(requestUrl).build(); | ||||
|     Call call = client.newCall(request); | ||||
| 
 | ||||
|     //请求加入调度
 | ||||
|     call.enqueue(new Callback() { | ||||
|       @Override public void onFailure(Call call, IOException e) { | ||||
|         L.e(TAG, "请求链接【" + url + "】失败"); | ||||
|         String data = null; | ||||
|         if (useCache) { | ||||
|           data = mCacheUtil.getStringCache(url + L.m2s(params)); | ||||
|           L.d(TAG, "数据获取成功,获取到的数据为 >>>> "); | ||||
|           L.j(data); | ||||
|         } | ||||
|         if (TextUtils.isEmpty(data)) { | ||||
|           setOnError(request, absResponse); | ||||
|         } else { | ||||
|           setOnResponse(data, absResponse); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       @Override public void onResponse(Call call, Response response) throws IOException { | ||||
|         String data = response.body().string(); | ||||
|         L.d(TAG, "数据获取成功,获取到的数据为 >>>> "); | ||||
|         L.j(data); | ||||
|         if (useCache) { | ||||
|           L.v(TAG, "缓存链接【" + url + "】的数据"); | ||||
|           mCacheUtil.putStringCache(url + L.m2s(params), data); | ||||
|         } | ||||
|         setOnResponse(data, absResponse); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 基本的Post方法 | ||||
|    */ | ||||
|   public void post(final @NonNull String url, final Map<String, String> params, | ||||
|       final Map<String, String> header, @NonNull final IResponse absResponse, | ||||
|       final boolean useCache) { | ||||
|     L.v(TAG, "请求链接 >>>> " + url); | ||||
|     OkHttpClient client = new OkHttpClient.Builder().connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS) | ||||
|         .writeTimeout(TIME_OUT, TimeUnit.MILLISECONDS) | ||||
|         .readTimeout(300000, TimeUnit.MILLISECONDS) | ||||
|         .build(); | ||||
|     FormBody.Builder formB = new FormBody.Builder(); | ||||
|     //头数据
 | ||||
|     Headers.Builder hb = new Headers.Builder(); | ||||
|     if (header != null && header.size() > 0) { | ||||
|       Set<String> keys = header.keySet(); | ||||
|       for (String key : keys) { | ||||
|         hb.add(key, header.get(key)); | ||||
|       } | ||||
|       L.v(TAG, "请求的头数据为 >>>> "); | ||||
|       L.m(header); | ||||
|     } | ||||
|     //请求参数
 | ||||
|     if (params != null && params.size() > 0) { | ||||
|       Set<String> keys = params.keySet(); | ||||
|       for (String key : keys) { | ||||
|         formB.add(key, params.get(key)); | ||||
|       } | ||||
|       L.v(TAG, "请求参数为 >>>> "); | ||||
|       L.m(params); | ||||
|     } else { | ||||
|       formB.add("null", "null"); | ||||
|     } | ||||
| 
 | ||||
|     Request request = | ||||
|         new Request.Builder().url(url).post(formB.build()).headers(hb.build()).build(); | ||||
|     Call call = client.newCall(request); | ||||
|     call.enqueue(new Callback() { | ||||
|       @Override public void onFailure(Call call, IOException e) { | ||||
|         L.e(TAG, "请求链接【" + url + "】失败"); | ||||
|         String data = null; | ||||
|         if (useCache) { | ||||
|           data = mCacheUtil.getStringCache(url + L.m2s(params)); | ||||
|           L.d(TAG, "从缓存读取的数据为 >>>> "); | ||||
|           L.j(data); | ||||
|         } | ||||
|         if (TextUtils.isEmpty(data)) { | ||||
|           setOnError(call, absResponse); | ||||
|         } else { | ||||
|           setOnResponse(data, absResponse); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       @Override public void onResponse(Call call, Response response) throws IOException { | ||||
|         String data = response.body().string(); | ||||
|         L.d(TAG, "数据获取成功,获取到的数据为 >>>>"); | ||||
|         L.j(data); | ||||
|         if (useCache) { | ||||
|           L.v(TAG, "缓存链接【" + url + "】的数据"); | ||||
|           mCacheUtil.putStringCache(url + L.m2s(params), data); | ||||
|         } | ||||
|         setOnResponse(data, absResponse); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   private void setOnError(final Object error, final IResponse response) { | ||||
|     mHandler.post(new Runnable() { | ||||
|       @Override public void run() { | ||||
|         response.onError(error); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   private void setOnResponse(final String data, final IResponse response) { | ||||
|     mHandler.post(new Runnable() { | ||||
|       @Override public void run() { | ||||
|         response.onResponse(data); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回String类型的响应 | ||||
|    */ | ||||
|   public static class AbsResponse implements IResponse { | ||||
| 
 | ||||
|     @Override public void onResponse(String data) { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override public void onError(Object error) { | ||||
| 
 | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,41 @@ | ||||
| //package com.arialyy.frame.http;
 | ||||
| //
 | ||||
| //import java.util.concurrent.TimeUnit;
 | ||||
| //
 | ||||
| //import javax.inject.Singleton;
 | ||||
| //
 | ||||
| //import okhttp3.OkHttpClient;
 | ||||
| //import dagger.Module;
 | ||||
| //import dagger.Provides;
 | ||||
| //import okhttp3.logging.HttpLoggingInterceptor;
 | ||||
| //import retrofit2.Retrofit;
 | ||||
| //import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
 | ||||
| //import retrofit2.converter.gson.GsonConverterFactory;
 | ||||
| //
 | ||||
| //@Module
 | ||||
| //public class WebApiModule {
 | ||||
| //    @Provides
 | ||||
| //    @Singleton
 | ||||
| //    public OkHttpClient provideOkHttpClient() {
 | ||||
| //        final OkHttpClient.Builder builder = new OkHttpClient.Builder();
 | ||||
| ////        if (BuildConfig.DEBUG) {
 | ||||
| //            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
 | ||||
| //            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
 | ||||
| //            builder.addInterceptor(logging);
 | ||||
| ////        }
 | ||||
| //        builder.connectTimeout(60 * 1000, TimeUnit.MILLISECONDS)
 | ||||
| //                .readTimeout(60 * 1000, TimeUnit.MILLISECONDS);
 | ||||
| //        return builder.build();
 | ||||
| //    }
 | ||||
| //
 | ||||
| //    @Provides
 | ||||
| //    @Singleton
 | ||||
| //    public Retrofit provideRetrofit(OkHttpClient okHttpClient) {
 | ||||
| //        Retrofit.Builder builder = new Retrofit.Builder();
 | ||||
| //        builder.client(okHttpClient)
 | ||||
| ////                .baseUrl(GameConstant.PACKAGE_TEST_BASE_URL)
 | ||||
| //                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 | ||||
| //                .addConverterFactory(GsonConverterFactory.create());
 | ||||
| //        return builder.build();
 | ||||
| //    }
 | ||||
| //}
 | ||||
| @ -0,0 +1,39 @@ | ||||
| package com.arialyy.frame.http.inf; | ||||
| 
 | ||||
| import android.support.annotation.NonNull; | ||||
| 
 | ||||
| /** | ||||
|  * 网络请求类 | ||||
|  */ | ||||
| public interface IRequest<T> { | ||||
|   /** | ||||
|    * post请求 | ||||
|    * | ||||
|    * @param url 请求连接 | ||||
|    * @param param 请求参数 | ||||
|    * @param headers 请求头信息 | ||||
|    * @param usCache 是否使用缓存 | ||||
|    * @param body 请求主体 | ||||
|    * @param response 回调接口 | ||||
|    */ | ||||
|   public void post(@NonNull String url, T param, T headers, boolean usCache, byte[] body, | ||||
|       @NonNull IResponse response); | ||||
| 
 | ||||
|   /** | ||||
|    * get请求 | ||||
|    * | ||||
|    * @param url 请求连接 | ||||
|    * @param param 请求参数 | ||||
|    * @param headers 请求头信息 | ||||
|    * @param usCache 是否使用缓存 | ||||
|    * @param body 请求主体 | ||||
|    * @param response 回调接口 | ||||
|    */ | ||||
|   public void get(@NonNull String url, T param, T headers, boolean usCache, byte[] body, | ||||
|       @NonNull IResponse response); | ||||
| 
 | ||||
|   /** | ||||
|    * 默认缓存文件夹 | ||||
|    */ | ||||
|   public static final String NET_CACHE_DIR = "HttpCache"; | ||||
| } | ||||
| @ -0,0 +1,16 @@ | ||||
| package com.arialyy.frame.http.inf; | ||||
| 
 | ||||
| /** | ||||
|  * 数据响应接口 | ||||
|  */ | ||||
| public interface IResponse { | ||||
|   /** | ||||
|    * 响应的数据回调 | ||||
|    */ | ||||
|   public void onResponse(String data); | ||||
| 
 | ||||
|   /** | ||||
|    * 错误返回回掉 | ||||
|    */ | ||||
|   public void onError(Object error); | ||||
| } | ||||
| @ -0,0 +1,143 @@ | ||||
| package com.arialyy.frame.module; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| 
 | ||||
| import android.databinding.ViewDataBinding; | ||||
| import com.arialyy.frame.core.AbsActivity; | ||||
| import com.arialyy.frame.core.BindingFactory; | ||||
| import com.arialyy.frame.module.inf.ModuleListener; | ||||
| import com.arialyy.frame.util.StringUtil; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| 
 | ||||
| /** | ||||
|  * Created by AriaLyy on 2015/2/3. | ||||
|  * 抽象的module | ||||
|  */ | ||||
| public class AbsModule { | ||||
|   public String TAG = ""; | ||||
|   private Context mContext; | ||||
|   private ModuleListener mModuleListener; | ||||
|   private OnCallback mCallback; | ||||
|   private BindingFactory mBindingFactory; | ||||
|   private Object mHost; | ||||
| 
 | ||||
|   public interface OnCallback { | ||||
|     public void onSuccess(int result, Object success); | ||||
| 
 | ||||
|     public void onError(int result, Object error); | ||||
|   } | ||||
| 
 | ||||
|   public AbsModule(Context context) { | ||||
|     mContext = context; | ||||
|     init(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 初始化一些东西 | ||||
|    */ | ||||
|   private void init() { | ||||
|     TAG = StringUtil.getClassName(this); | ||||
|     mBindingFactory = BindingFactory.newInstance(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置Module监听 | ||||
|    * | ||||
|    * @param moduleListener Module监听 | ||||
|    */ | ||||
|   public void setModuleListener(ModuleListener moduleListener) { | ||||
|     if (moduleListener == null) throw new NullPointerException("ModuleListener不能为空"); | ||||
|     this.mModuleListener = moduleListener; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 为Binding设置寄主 | ||||
|    */ | ||||
|   public void setHost(Object host) { | ||||
|     mHost = host; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 成功的回调 | ||||
|    */ | ||||
|   private void successCallback(int key, Object obj) { | ||||
|     if (mCallback == null) { | ||||
|       L.e(TAG, "OnCallback 为 null"); | ||||
|       return; | ||||
|     } | ||||
|     mCallback.onSuccess(key, obj); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 失败的回调 | ||||
|    */ | ||||
|   public void errorCallback(int key, Object obj) { | ||||
|     if (mCallback == null) { | ||||
|       L.e(TAG, "OnCallback 为 null"); | ||||
|       return; | ||||
|     } | ||||
|     mCallback.onError(key, obj); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取Context | ||||
|    * | ||||
|    * @return Context | ||||
|    */ | ||||
|   public Context getContext() { | ||||
|     return mContext; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置Module回调 | ||||
|    * | ||||
|    * @param callback Module 回调 | ||||
|    */ | ||||
|   public void setCallback(OnCallback callback) { | ||||
|     mCallback = callback; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取ViewDataBinding | ||||
|    * | ||||
|    * @param clazz ViewDataBinding实例 | ||||
|    */ | ||||
|   protected <VB extends ViewDataBinding> VB getBinding(Class<VB> clazz) { | ||||
|     return mBindingFactory.getBinding(mHost, clazz); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 统一的回调,如果已经设置了OnCallback,则使用OnCallback; | ||||
|    * 否则将使用dataCallback,{@link AbsActivity#dataCallback(int, Object)} | ||||
|    * | ||||
|    * @param result 返回码 | ||||
|    * @param data 回调数据 | ||||
|    */ | ||||
|   protected void callback(final int result, final Object data) { | ||||
|     if (mCallback != null) { | ||||
|       successCallback(result, data); | ||||
|       return; | ||||
|     } | ||||
|     mModuleListener.callback(result, data); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * module回调 | ||||
|    * | ||||
|    * @param method 回调的方法名 | ||||
|    */ | ||||
|   @Deprecated protected void callback(String method) { | ||||
|     mModuleListener.callback(method); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 带参数的module回调 | ||||
|    * | ||||
|    * @param method 回调的方法名 | ||||
|    * @param dataClassType 回调数据类型 | ||||
|    * @param data 回调数据 | ||||
|    */ | ||||
|   @Deprecated protected void callback(String method, Class<?> dataClassType, Object data) { | ||||
|     mModuleListener.callback(method, dataClassType, data); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,112 @@ | ||||
| package com.arialyy.frame.module; | ||||
| 
 | ||||
| import com.arialyy.frame.module.inf.ModuleListener; | ||||
| import com.arialyy.frame.util.ReflectionUtil; | ||||
| import com.arialyy.frame.util.show.FL; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| 
 | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | ||||
| 
 | ||||
| /** | ||||
|  * Created by AriaLyy on 2015/2/3. | ||||
|  * 代理对象 | ||||
|  */ | ||||
| public class IOCProxy implements ModuleListener { | ||||
|   private static final String TAG = "IOCProxy"; | ||||
|   private static final String mMethod = "dataCallback"; | ||||
| 
 | ||||
|   private Object mObj; | ||||
| 
 | ||||
|   /** | ||||
|    * 初始化静态代理 | ||||
|    */ | ||||
|   public static IOCProxy newInstance(Object obj, AbsModule module) { | ||||
|     return new IOCProxy(obj, module); | ||||
|   } | ||||
| 
 | ||||
|   public static IOCProxy newInstance(Object obj) { | ||||
|     return new IOCProxy(obj, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 被代理对象 | ||||
|    */ | ||||
|   private IOCProxy(Object obj, AbsModule module) { | ||||
|     this.mObj = obj; | ||||
| 
 | ||||
|     if (module != null) { | ||||
|       module.setModuleListener(this); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public void changeModule(AbsModule module) { | ||||
|     module.setModuleListener(this); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 统一的数据回调 | ||||
|    * | ||||
|    * @param result 返回码 | ||||
|    * @param data 回调数据 | ||||
|    */ | ||||
|   @Override public void callback(int result, Object data) { | ||||
|     synchronized (this) { | ||||
|       try { | ||||
|         Method m = ReflectionUtil.getMethod(mObj.getClass(), mMethod, int.class, Object.class); | ||||
|         m.setAccessible(true); | ||||
|         m.invoke(mObj, result, data); | ||||
|       } catch (InvocationTargetException e) { | ||||
|         e.printStackTrace(); | ||||
|       } catch (IllegalAccessException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 数据回调 | ||||
|    * | ||||
|    * @param method 方法名 | ||||
|    */ | ||||
|   @Override @Deprecated public void callback(String method) { | ||||
|     synchronized (this) { | ||||
|       try { | ||||
|         Method m = mObj.getClass().getDeclaredMethod(method); | ||||
|         m.setAccessible(true); | ||||
|         m.invoke(mObj); | ||||
|       } catch (NoSuchMethodException e) { | ||||
|         L.e(TAG, "无法找到" + method + "方法"); | ||||
|         FL.e(TAG, FL.getExceptionString(e)); | ||||
|       } catch (InvocationTargetException e) { | ||||
|         e.printStackTrace(); | ||||
|       } catch (IllegalAccessException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 带参数的回调 | ||||
|    * | ||||
|    * @param method 方法名 | ||||
|    * @param dataClassType 参数类型,如 int.class | ||||
|    * @param data 数据 | ||||
|    */ | ||||
|   @Override @Deprecated public void callback(String method, Class<?> dataClassType, Object data) { | ||||
|     synchronized (this) { | ||||
|       try { | ||||
|         Method m = mObj.getClass().getDeclaredMethod(method, dataClassType); | ||||
|         m.setAccessible(true); | ||||
|         m.invoke(mObj, data); | ||||
|       } catch (NoSuchMethodException e) { | ||||
|         L.e(TAG, "无法找到" + method + "方法"); | ||||
|         FL.e(TAG, FL.getExceptionString(e)); | ||||
|       } catch (InvocationTargetException e) { | ||||
|         e.printStackTrace(); | ||||
|       } catch (IllegalAccessException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,61 @@ | ||||
| package com.arialyy.frame.module; | ||||
| 
 | ||||
| import android.util.SparseIntArray; | ||||
| 
 | ||||
| import com.arialyy.frame.util.ObjUtil; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.HashSet; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/7/7. | ||||
|  */ | ||||
| public class ModuleFactory { | ||||
|   private Map<Set<Integer>, AbsModule.OnCallback> mPool = new HashMap<>(); | ||||
|   private SparseIntArray mKeyIndex = new SparseIntArray(); | ||||
|   private static final String TAG = "ModuleFactory"; | ||||
| 
 | ||||
|   public ModuleFactory() { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   public void addCallback(int key, AbsModule.OnCallback callback) { | ||||
|     if (checkKey(key, callback)) { | ||||
|       L.e(TAG, "key 已经和 callback对应"); | ||||
|       return; | ||||
|     } | ||||
|     if (mPool.containsValue(callback)) { | ||||
|       Set<Integer> oldKeys = ObjUtil.getKeyByValue(mPool, callback); | ||||
|       if (oldKeys != null) { | ||||
|         if (!oldKeys.contains(key)) { | ||||
|           oldKeys.add(key); | ||||
|           mKeyIndex.put(key, callback.hashCode()); | ||||
|         } | ||||
|       } else { | ||||
|         oldKeys = new HashSet<>(); | ||||
|         oldKeys.add(key); | ||||
|         mPool.put(oldKeys, callback); | ||||
|         mKeyIndex.put(key, callback.hashCode()); | ||||
|       } | ||||
|     } else { | ||||
|       Set<Integer> newKeys = new HashSet<>(); | ||||
|       newKeys.add(key); | ||||
|       mPool.put(newKeys, callback); | ||||
|       mKeyIndex.put(key, callback.hashCode()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 检查key和callback的对应关系 | ||||
|    * | ||||
|    * @return true : key已经和value对应,false : key没有和value对应 | ||||
|    */ | ||||
|   private boolean checkKey(int key, AbsModule.OnCallback callback) { | ||||
|     return mKeyIndex.indexOfKey(key) != -1 | ||||
|         || mKeyIndex.indexOfValue(callback.hashCode()) != -1 | ||||
|         && mKeyIndex.valueAt(callback.hashCode()) == key; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,31 @@ | ||||
| package com.arialyy.frame.module.inf; | ||||
| 
 | ||||
| /** | ||||
|  * Created by AriaLyy on 2015/2/3. | ||||
|  * Module监听 | ||||
|  */ | ||||
| public interface ModuleListener { | ||||
|   /** | ||||
|    * 无参的回调 | ||||
|    * | ||||
|    * @param method 方法名 | ||||
|    */ | ||||
|   public void callback(String method); | ||||
| 
 | ||||
|   /** | ||||
|    * 带参数的回调 | ||||
|    * | ||||
|    * @param method 方法名 | ||||
|    * @param dataClassType 参数类型 | ||||
|    * @param data 数据 | ||||
|    */ | ||||
|   public void callback(String method, Class<?> dataClassType, Object data); | ||||
| 
 | ||||
|   /** | ||||
|    * 统一接口的回调,回调接口为dataCallback | ||||
|    * | ||||
|    * @param result 返回码 | ||||
|    * @param data 回调数据 | ||||
|    */ | ||||
|   public void callback(int result, Object data); | ||||
| } | ||||
| @ -0,0 +1,14 @@ | ||||
| package com.arialyy.frame.permission; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/4/11. | ||||
|  * 权限回调 | ||||
|  */ | ||||
| public interface OnPermissionCallback { | ||||
|   public static final int PERMISSION_ALERT_WINDOW = 0xad1; | ||||
|   public static final int PERMISSION_WRITE_SETTING = 0xad2; | ||||
| 
 | ||||
|   public void onSuccess(String... permissions); | ||||
| 
 | ||||
|   public void onFail(String... permissions); | ||||
| } | ||||
| @ -0,0 +1,143 @@ | ||||
| package com.arialyy.frame.permission; | ||||
| 
 | ||||
| import android.annotation.TargetApi; | ||||
| import android.app.Activity; | ||||
| import android.os.Build; | ||||
| import android.provider.Settings; | ||||
| import android.support.v4.app.Fragment; | ||||
| import android.util.SparseArray; | ||||
| 
 | ||||
| import com.arialyy.frame.util.show.L; | ||||
| 
 | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/4/11. | ||||
|  * 权限管理工具类 | ||||
|  */ | ||||
| @TargetApi(Build.VERSION_CODES.M) public class PermissionManager implements OnPermissionCallback { | ||||
|   private static final String TAG = "PermissionManager"; | ||||
|   private PermissionUtil mPu; | ||||
|   private SparseArray<OnPermissionCallback> mCallbacks = new SparseArray<>(); | ||||
|   private static volatile PermissionManager INSTANCE = null; | ||||
|   private static final Object LOCK = new Object(); | ||||
| 
 | ||||
|   public static PermissionManager getInstance() { | ||||
|     if (INSTANCE == null) { | ||||
|       synchronized (LOCK) { | ||||
|         INSTANCE = new PermissionManager(); | ||||
|       } | ||||
|     } | ||||
|     return INSTANCE; | ||||
|   } | ||||
| 
 | ||||
|   private PermissionManager() { | ||||
|     mPu = PermissionUtil.getInstance(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 检查权限 | ||||
|    * | ||||
|    * @param permission 需要检查的权限 | ||||
|    * @return true:已经授权 | ||||
|    */ | ||||
|   public boolean checkPermission(Activity activity, String permission) { | ||||
|     return mPu.checkPermission(activity, permission); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 检查权限 | ||||
|    * | ||||
|    * @param permission 需要检查的权限 | ||||
|    * @return true:已经授权 | ||||
|    */ | ||||
|   public boolean checkPermission(Fragment fragment, String permission) { | ||||
|     Activity activity = fragment.getActivity(); | ||||
|     return checkPermission(activity, permission); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 申请悬浮框权限 | ||||
|    * | ||||
|    * @param obj obj 只能是Activity、Fragment 的子类及其衍生类 | ||||
|    */ | ||||
|   public void requestAlertWindowPermission(Object obj, OnPermissionCallback callback) { | ||||
|     int hashCode = Arrays.hashCode(new String[] { Settings.ACTION_MANAGE_OVERLAY_PERMISSION }); | ||||
|     registerCallback(callback, hashCode); | ||||
|     mPu.requestAlertWindowPermission(obj); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 申请修改系统设置权限 | ||||
|    * | ||||
|    * @param obj obj 只能是Activity、Fragment 的子类及其衍生类 | ||||
|    */ | ||||
|   public void requestWriteSettingPermission(Object obj, OnPermissionCallback callback) { | ||||
|     int hashCode = Arrays.hashCode(new String[] { Settings.ACTION_MANAGE_WRITE_SETTINGS }); | ||||
|     registerCallback(callback, hashCode); | ||||
|     mPu.requestWriteSetting(obj); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 申请权限 | ||||
|    * | ||||
|    * @param obj Activity || Fragment | ||||
|    * @param permission 权限 | ||||
|    */ | ||||
|   public void requestPermission(Object obj, OnPermissionCallback callback, String... permission) { | ||||
|     requestPermission(obj, "", callback, registerCallback(obj, callback, permission)); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 申请权限 | ||||
|    * | ||||
|    * @param obj Activity || Fragment | ||||
|    * @param hint 如果框对话框包含“不再询问”选择框的时候的提示用语。 | ||||
|    * @param permission 权限 | ||||
|    */ | ||||
|   private void requestPermission(Object obj, String hint, OnPermissionCallback callback, | ||||
|       String... permission) { | ||||
|     mPu.requestPermission(obj, hint, 0, registerCallback(obj, callback, permission)); | ||||
|   } | ||||
| 
 | ||||
|   private void registerCallback(OnPermissionCallback callback, int hashCode) { | ||||
|     OnPermissionCallback c = mCallbacks.get(hashCode); | ||||
|     if (c == null) { | ||||
|       mCallbacks.append(hashCode, callback); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private String[] registerCallback(Object obj, OnPermissionCallback callback, | ||||
|       String... permission) { | ||||
|     List<String> list = mPu.checkPermission(obj, permission); | ||||
|     if (list == null || list.size() == 0) { | ||||
|       return null; | ||||
|     } | ||||
|     String[] denyPermission = mPu.list2Array(list); | ||||
|     int hashCode = Arrays.hashCode(denyPermission); | ||||
|     OnPermissionCallback c = mCallbacks.get(hashCode); | ||||
|     if (c == null) { | ||||
|       mCallbacks.append(hashCode, callback); | ||||
|     } | ||||
|     return denyPermission; | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onSuccess(String... permissions) { | ||||
|     int hashCode = Arrays.hashCode(permissions); | ||||
|     OnPermissionCallback c = mCallbacks.get(hashCode); | ||||
|     if (c != null) { | ||||
|       c.onSuccess(permissions); | ||||
|       mCallbacks.remove(hashCode); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onFail(String... permissions) { | ||||
|     int hashCode = Arrays.hashCode(permissions); | ||||
|     OnPermissionCallback c = mCallbacks.get(hashCode); | ||||
|     if (c != null) { | ||||
|       c.onFail(permissions); | ||||
|       mCallbacks.remove(hashCode); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,201 @@ | ||||
| package com.arialyy.frame.permission; | ||||
| 
 | ||||
| import android.annotation.TargetApi; | ||||
| import android.app.Activity; | ||||
| import android.content.Intent; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.provider.Settings; | ||||
| import android.support.v4.app.Fragment; | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| import com.arialyy.frame.util.AndroidVersionUtil; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| import com.arialyy.frame.util.show.T; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/4/11. | ||||
|  * 6.0权限帮助工具 | ||||
|  */ | ||||
| @TargetApi(Build.VERSION_CODES.M) class PermissionUtil { | ||||
|   public static final Object LOCK = new Object(); | ||||
|   public volatile static PermissionUtil INSTANCE = null; | ||||
|   private static final String TAG = "PermissionUtil"; | ||||
| 
 | ||||
|   public static PermissionUtil getInstance() { | ||||
|     if (INSTANCE == null) { | ||||
|       synchronized (LOCK) { | ||||
|         INSTANCE = new PermissionUtil(); | ||||
|       } | ||||
|     } | ||||
|     return INSTANCE; | ||||
|   } | ||||
| 
 | ||||
|   private PermissionUtil() { | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 申请权限 | ||||
|    */ | ||||
|   public void requestPermission(Object obj, int requestCode, String... permission) { | ||||
|     if (!AndroidVersionUtil.hasM()) { | ||||
|       return; | ||||
|     } | ||||
|     requestPermission(obj, "", requestCode, permission); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 申请权限 | ||||
|    * | ||||
|    * @param hint 如果框对话框包含”不再询问“选择框的时候的提示用语。 | ||||
|    */ | ||||
|   public void requestPermission(Object obj, String hint, int requestCode, String... permission) { | ||||
|     if (!AndroidVersionUtil.hasM() || permission == null || permission.length == 0) { | ||||
|       return; | ||||
|     } | ||||
|     Activity activity = null; | ||||
|     Fragment fragment = null; | ||||
|     if (obj instanceof Activity) { | ||||
|       activity = (Activity) obj; | ||||
|     } else if (obj instanceof Fragment) { | ||||
|       fragment = (Fragment) obj; | ||||
|       activity = fragment.getActivity(); | ||||
|     } else { | ||||
|       L.e(TAG, "obj 只能是 Activity 或者 fragment 及其子类"); | ||||
|       return; | ||||
|     } | ||||
|     if (!TextUtils.isEmpty(hint)) { | ||||
|       for (String str : permission) { | ||||
|         if (fragment != null) { | ||||
|           if (fragment.shouldShowRequestPermissionRationale(str)) { | ||||
|             T.showShort(fragment.getContext(), hint); | ||||
|             break; | ||||
|           } | ||||
|         } else { | ||||
|           if (activity.shouldShowRequestPermissionRationale(str)) { | ||||
|             T.showShort(activity, hint); | ||||
|             break; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     if (fragment != null) { | ||||
|       fragment.requestPermissions(permission, requestCode); | ||||
|     } else { | ||||
|       activity.requestPermissions(permission, requestCode); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   protected String[] list2Array(List<String> denyPermission) { | ||||
|     String[] array = new String[denyPermission.size()]; | ||||
|     for (int i = 0, count = denyPermission.size(); i < count; i++) { | ||||
|       array[i] = denyPermission.get(i); | ||||
|     } | ||||
|     return array; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 检查没有被授权的权限 | ||||
|    */ | ||||
|   public List<String> checkPermission(Object obj, String... permission) { | ||||
|     if (!AndroidVersionUtil.hasM() || permission == null || permission.length == 0) { | ||||
|       return null; | ||||
|     } | ||||
|     Activity activity = null; | ||||
|     if (obj instanceof Activity) { | ||||
|       activity = (Activity) obj; | ||||
|     } else if (obj instanceof Fragment) { | ||||
|       activity = ((Fragment) obj).getActivity(); | ||||
|     } else { | ||||
|       L.e(TAG, "obj 只能是 Activity 或者 fragment 及其子类"); | ||||
|       return null; | ||||
|     } | ||||
|     List<String> denyPermissions = new ArrayList<>(); | ||||
|     for (String p : permission) { | ||||
|       if (activity.checkSelfPermission(p) != PackageManager.PERMISSION_GRANTED) { | ||||
|         denyPermissions.add(p); | ||||
|       } | ||||
|     } | ||||
|     return denyPermissions; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 检查应用是否有该权限 | ||||
|    * | ||||
|    * @param permission 权限,Manifest.permission.CAMERA | ||||
|    * @return true ==> 已经授权 | ||||
|    */ | ||||
|   public boolean checkPermission(Activity activity, String permission) { | ||||
|     return AndroidVersionUtil.hasM() | ||||
|         && activity.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED; | ||||
|   } | ||||
| 
 | ||||
|   /* | ||||
|    * 请求悬浮权限 | ||||
|    * 在onActivityResult里面添加以下代码 | ||||
|    * protected void onActivityResult(int requestCode, int resultCode, Intent data) { | ||||
|    *      super.onActivityResult(requestCode, resultCode, data); | ||||
|    *      if (requestCode == OnPermissionCallback.PERMISSION_ALERT_WINDOW) { | ||||
|    *          if (Settings.canDrawOverlays(this)) {       //在这判断是否请求权限成功
 | ||||
|    *              Log.i(LOGTAG, "onActivityResult granted"); | ||||
|    *          } | ||||
|    *      } | ||||
|    * } | ||||
|    * | ||||
|    * @param obj | ||||
|    */ | ||||
|   public void requestAlertWindowPermission(Object obj) { | ||||
|     if (!AndroidVersionUtil.hasM()) { | ||||
|       return; | ||||
|     } | ||||
|     Activity activity = null; | ||||
|     Fragment fragment = null; | ||||
|     if (obj instanceof Activity) { | ||||
|       activity = (Activity) obj; | ||||
|     } else if (obj instanceof Fragment) { | ||||
|       fragment = (Fragment) obj; | ||||
|       activity = fragment.getActivity(); | ||||
|     } else { | ||||
|       L.e(TAG, "obj 只能是 Activity 或者 fragment 及其衍生类"); | ||||
|       return; | ||||
|     } | ||||
|     Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); | ||||
|     intent.setData(Uri.parse("package:" + activity.getPackageName())); | ||||
|     if (fragment != null) { | ||||
|       fragment.startActivityForResult(intent, OnPermissionCallback.PERMISSION_ALERT_WINDOW); | ||||
|     } else { | ||||
|       activity.startActivityForResult(intent, OnPermissionCallback.PERMISSION_ALERT_WINDOW); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 请求修改系统设置权限 | ||||
|    */ | ||||
|   public void requestWriteSetting(Object obj) { | ||||
|     if (!AndroidVersionUtil.hasM()) { | ||||
|       return; | ||||
|     } | ||||
|     Activity activity = null; | ||||
|     Fragment fragment = null; | ||||
|     if (obj instanceof Activity) { | ||||
|       activity = (Activity) obj; | ||||
|     } else if (obj instanceof Fragment) { | ||||
|       fragment = (Fragment) obj; | ||||
|       activity = fragment.getActivity(); | ||||
|     } else { | ||||
|       L.e(TAG, "obj 只能是 Activity 或者 fragment 及其衍生类"); | ||||
|       return; | ||||
|     } | ||||
|     Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS); | ||||
|     intent.setData(Uri.parse("package:" + activity.getPackageName())); | ||||
|     if (fragment != null) { | ||||
|       fragment.startActivityForResult(intent, OnPermissionCallback.PERMISSION_WRITE_SETTING); | ||||
|     } else { | ||||
|       activity.startActivityForResult(intent, OnPermissionCallback.PERMISSION_WRITE_SETTING); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,74 @@ | ||||
| package com.arialyy.frame.temp; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.util.AttributeSet; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.widget.LinearLayout; | ||||
| 
 | ||||
| import com.arialyy.frame.util.StringUtil; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/4/27. | ||||
|  * 抽象的填充类 | ||||
|  */ | ||||
| public abstract class AbsTempView extends LinearLayout implements ITempView { | ||||
|   private OnTempBtClickListener mBtListener; | ||||
|   private static String TAG; | ||||
|   protected int mType = ERROR; | ||||
| 
 | ||||
|   public AbsTempView(Context context) { | ||||
|     this(context, null); | ||||
|   } | ||||
| 
 | ||||
|   public AbsTempView(Context context, AttributeSet attrs) { | ||||
|     super(context, attrs); | ||||
|     initView(context); | ||||
|   } | ||||
| 
 | ||||
|   private void initView(Context context) { | ||||
|     View view = LayoutInflater.from(context).inflate(setLayoutId(), this); | ||||
|     TAG = StringUtil.getClassName(this); | ||||
|     init(); | ||||
|   } | ||||
| 
 | ||||
|   protected abstract void init(); | ||||
| 
 | ||||
|   /** | ||||
|    * 如果界面有按钮,则需要对着按钮的点击事件进行监听 | ||||
|    */ | ||||
|   public void setBtListener(@NonNull OnTempBtClickListener listener) { | ||||
|     mBtListener = listener; | ||||
|   } | ||||
| 
 | ||||
|   protected abstract int setLayoutId(); | ||||
| 
 | ||||
|   /** | ||||
|    * 将按钮点击事件传递给TempView调用类 | ||||
|    * | ||||
|    * @param type {@link ITempView} | ||||
|    */ | ||||
|   protected void onTempBtClick(View view, int type) { | ||||
|     if (mBtListener != null) { | ||||
|       mBtListener.onBtTempClick(view, type); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override public void setType(int type) { | ||||
|     mType = type; | ||||
|     if (type == LOADING) { | ||||
|       onLoading(); | ||||
|       return; | ||||
|     } | ||||
|     if (type == ERROR) { | ||||
|       onError(); | ||||
|     } else if (type == DATA_NULL) { | ||||
|       onNull(); | ||||
|     } else { | ||||
|       L.e(TAG, "类型错误"); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,34 @@ | ||||
| package com.arialyy.frame.temp; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/4/27. | ||||
|  */ | ||||
| public interface ITempView { | ||||
|   public static final int ERROR = 0xaff1; | ||||
|   public static final int DATA_NULL = 0xaff2; | ||||
|   public static final int LOADING = 0xaff3; | ||||
| 
 | ||||
|   /** | ||||
|    * 设置填充界面类型 | ||||
|    * | ||||
|    * @param type {@link ITempView#ERROR} | ||||
|    * {@link ITempView#DATA_NULL} | ||||
|    * {@link ITempView#LOADING} | ||||
|    */ | ||||
|   public void setType(int type); | ||||
| 
 | ||||
|   /** | ||||
|    * 在这处理type = ITempView#ERROR 时的逻辑 | ||||
|    */ | ||||
|   public void onError(); | ||||
| 
 | ||||
|   /** | ||||
|    * 在这处理type = ITempView#DATA_NULL 时的逻辑 | ||||
|    */ | ||||
|   public void onNull(); | ||||
| 
 | ||||
|   /** | ||||
|    * 在这处理type = ITempView#LOADING 时的逻辑 | ||||
|    */ | ||||
|   public void onLoading(); | ||||
| } | ||||
| @ -0,0 +1,10 @@ | ||||
| package com.arialyy.frame.temp; | ||||
| 
 | ||||
| import android.view.View; | ||||
| 
 | ||||
| public interface OnTempBtClickListener { | ||||
|   /** | ||||
|    * @param type {@link ITempView#ERROR}, {@link ITempView#DATA_NULL}, {@link ITempView#LOADING} | ||||
|    */ | ||||
|   public void onBtTempClick(View view, int type); | ||||
| } | ||||
| @ -0,0 +1,60 @@ | ||||
| package com.arialyy.frame.temp; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.view.View; | ||||
| import android.widget.Button; | ||||
| import android.widget.FrameLayout; | ||||
| import android.widget.ProgressBar; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import com.lyy.frame.R; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/1/11. | ||||
|  * 错误填充View | ||||
|  */ | ||||
| public class TempView extends AbsTempView { | ||||
|   ProgressBar mPb; | ||||
|   TextView mHint; | ||||
|   Button mBt; | ||||
|   FrameLayout mErrorContent; | ||||
| 
 | ||||
|   public TempView(Context context) { | ||||
|     super(context); | ||||
|   } | ||||
| 
 | ||||
|   @Override protected void init() { | ||||
|     mPb = (ProgressBar) findViewById(R.id.pb); | ||||
|     mHint = (TextView) findViewById(R.id.hint); | ||||
|     mBt = (Button) findViewById(R.id.bt); | ||||
|     mErrorContent = (FrameLayout) findViewById(R.id.error); | ||||
|     mBt.setOnClickListener(new OnClickListener() { | ||||
|       @Override public void onClick(View v) { | ||||
|         onTempBtClick(v, mType); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   @Override protected int setLayoutId() { | ||||
|     return R.layout.layout_error_temp; | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onError() { | ||||
|     mErrorContent.setVisibility(VISIBLE); | ||||
|     mPb.setVisibility(GONE); | ||||
|     mHint.setText("网络错误"); | ||||
|     mBt.setText("点击刷新"); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onNull() { | ||||
|     mErrorContent.setVisibility(VISIBLE); | ||||
|     mPb.setVisibility(GONE); | ||||
|     mHint.setText("数据为空"); | ||||
|     mBt.setText("点击刷新"); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void onLoading() { | ||||
|     mErrorContent.setVisibility(GONE); | ||||
|     mPb.setVisibility(VISIBLE); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,156 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.annotation.SuppressLint; | ||||
| import android.support.annotation.NonNull; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.security.SecureRandom; | ||||
| 
 | ||||
| import javax.crypto.Cipher; | ||||
| import javax.crypto.KeyGenerator; | ||||
| import javax.crypto.SecretKey; | ||||
| import javax.crypto.spec.SecretKeySpec; | ||||
| 
 | ||||
| /** | ||||
|  * AES加密 | ||||
|  * | ||||
|  * @author lyy | ||||
|  */ | ||||
| public class AESEncryption { | ||||
|   /** | ||||
|    * 4.4的要Cipher cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding"); | ||||
|    */ | ||||
|   private static final int JELLY_BEAN_4_2 = 17; | ||||
| 
 | ||||
|   /** | ||||
|    * 加密文件 | ||||
|    * | ||||
|    * @param filePath 原始文件路径 | ||||
|    * @return 加密后的文件路径 | ||||
|    */ | ||||
|   public static String encryptFile(@NonNull String filePath) { | ||||
|     File file = new File(filePath); | ||||
|     return ""; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 加密函数 | ||||
|    * | ||||
|    * @param seed 密钥 | ||||
|    * @param cleartext 说要进行加密的密码 | ||||
|    * @return 返回的是16进制的加密类型 | ||||
|    * @throws Exception | ||||
|    */ | ||||
|   public static String encryptString(String seed, String cleartext) throws Exception { | ||||
|     byte[] rawKey = getRawKey(seed.getBytes()); | ||||
|     byte[] result = encryptByte(rawKey, cleartext.getBytes()); | ||||
|     return toHex(result); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 解密函数 | ||||
|    * | ||||
|    * @param seed 密钥 | ||||
|    * @param encrypted 进行加密后的密码 | ||||
|    * @return 返回原来的密码 | ||||
|    * @throws Exception | ||||
|    */ | ||||
|   public static String decryptString(String seed, String encrypted) throws Exception { | ||||
|     byte[] rawKey = getRawKey(seed.getBytes()); | ||||
|     byte[] enc = toByte(encrypted); | ||||
|     byte[] result = decryptByte(rawKey, enc); | ||||
|     return new String(result); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取key | ||||
|    * | ||||
|    * @throws Exception | ||||
|    */ | ||||
|   @SuppressLint("DeletedProvider") private static byte[] getRawKey(byte[] seed) throws Exception { | ||||
|     KeyGenerator kgen = KeyGenerator.getInstance("AES"); | ||||
| 
 | ||||
|     SecureRandom sr = null; | ||||
|     if (android.os.Build.VERSION.SDK_INT >= JELLY_BEAN_4_2) { | ||||
|       sr = SecureRandom.getInstance("SHA1PRNG", "Crypto"); | ||||
|     } else { | ||||
|       sr = SecureRandom.getInstance("SHA1PRNG"); | ||||
|     } | ||||
|     // SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
 | ||||
|     sr.setSeed(seed); | ||||
|     kgen.init(128, sr); // 192 and 256 bits may not be available
 | ||||
|     SecretKey skey = kgen.generateKey(); | ||||
|     return skey.getEncoded(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 4.3以上的要用cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding"); | ||||
|    * 加密byte流 | ||||
|    * | ||||
|    * @throws Exception | ||||
|    */ | ||||
|   private static byte[] encryptByte(byte[] raw, byte[] clear) throws Exception { | ||||
|     SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); | ||||
|     Cipher cipher = null; | ||||
|     if (android.os.Build.VERSION.SDK_INT > JELLY_BEAN_4_2) { | ||||
|       cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding"); | ||||
|     } else { | ||||
|       cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); | ||||
|     } | ||||
|     cipher.init(Cipher.ENCRYPT_MODE, skeySpec); | ||||
|     return cipher.doFinal(clear); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 4.3以上的要用cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding"); | ||||
|    * 解密byte流 | ||||
|    * | ||||
|    * @throws Exception | ||||
|    */ | ||||
|   private static byte[] decryptByte(byte[] raw, byte[] encrypted) throws Exception { | ||||
|     SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); | ||||
|     Cipher cipher = null; | ||||
|     if (android.os.Build.VERSION.SDK_INT > JELLY_BEAN_4_2) { | ||||
|       cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding"); | ||||
|     } else { | ||||
|       cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); | ||||
|     } | ||||
|     cipher.init(Cipher.DECRYPT_MODE, skeySpec); | ||||
|     return cipher.doFinal(encrypted); | ||||
|   } | ||||
| 
 | ||||
|   public static String toHex(String txt) { | ||||
|     return toHex(txt.getBytes()); | ||||
|   } | ||||
| 
 | ||||
|   public static String fromHex(String hex) { | ||||
|     return new String(toByte(hex)); | ||||
|   } | ||||
| 
 | ||||
|   public static byte[] toByte(String hexString) { | ||||
|     int len = hexString.length() / 2; | ||||
|     byte[] result = new byte[len]; | ||||
|     for (int i = 0; i < len; i++) | ||||
|       result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue(); | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 把用户的key转换为16为的key | ||||
|    * AES算法的秘钥要求16位 | ||||
|    */ | ||||
|   public static String toHex(byte[] buf) { | ||||
|     if (buf == null) return ""; | ||||
|     StringBuffer result = new StringBuffer(2 * buf.length); | ||||
|     for (byte aBuf : buf) { | ||||
|       appendHex(result, aBuf); | ||||
|     } | ||||
|     return result.toString(); | ||||
|   } | ||||
| 
 | ||||
|   private final static String HEX = "0123456789ABCDEF"; | ||||
| 
 | ||||
|   private static void appendHex(StringBuffer sb, byte b) { | ||||
|     sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f)); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,691 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.Manifest; | ||||
| import android.annotation.TargetApi; | ||||
| import android.app.Activity; | ||||
| import android.app.ActivityManager; | ||||
| import android.app.AlarmManager; | ||||
| import android.app.PendingIntent; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.pm.ApplicationInfo; | ||||
| import android.content.pm.PackageInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.content.pm.ResolveInfo; | ||||
| import android.content.res.Resources; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.os.Environment; | ||||
| import android.os.StatFs; | ||||
| import android.provider.Settings; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.v4.app.ActivityCompat; | ||||
| import android.telephony.TelephonyManager; | ||||
| import android.text.format.Formatter; | ||||
| import android.util.DisplayMetrics; | ||||
| import android.view.WindowManager; | ||||
| import com.arialyy.frame.util.show.FL; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| import java.io.BufferedReader; | ||||
| import java.io.DataOutputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| /** | ||||
|  * android系统工具类 | ||||
|  */ | ||||
| public class AndroidUtils { | ||||
|   private static final String TAG = "AndroidUtils"; | ||||
| 
 | ||||
|   private AndroidUtils() { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   private static final float DENSITY = Resources.getSystem().getDisplayMetrics().density; | ||||
| 
 | ||||
|   // 获得机身可用内存
 | ||||
|   public static String getRomAvailableSize(Context context) { | ||||
|     File path = Environment.getDataDirectory(); | ||||
|     StatFs stat = new StatFs(path.getPath()); | ||||
|     long blockSize = stat.getBlockSize(); | ||||
|     long availableBlocks = stat.getAvailableBlocks(); | ||||
|     return Formatter.formatFileSize(context, blockSize * availableBlocks); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 重启app | ||||
|    */ | ||||
|   public static void reStartApp(Context context) { | ||||
|     Intent intent = context.getPackageManager() | ||||
|         .getLaunchIntentForPackage(context.getPackageName()); | ||||
|     PendingIntent restartIntent = | ||||
|         PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT); | ||||
|     AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); | ||||
|     mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1秒钟后重启应用
 | ||||
|     System.exit(0); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 另外一种dp转PX方法 | ||||
|    */ | ||||
|   public static int dp2px(int dp) { | ||||
|     return Math.round(dp * DENSITY); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 检查权限 | ||||
|    * | ||||
|    * @param permission android.permission.WRITE_EXTERNAL_STORAGE | ||||
|    * @return manifest 已经定义了则返回true | ||||
|    */ | ||||
|   public static boolean checkPermission(@NonNull Context context, @NonNull String permission) { | ||||
|     return context.checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 申请root权限 | ||||
|    * | ||||
|    * @return 应用程序是/否获取Root权限 | ||||
|    */ | ||||
|   public static boolean getRootPermission(String pkgCodePath) { | ||||
|     Process process = null; | ||||
|     DataOutputStream os = null; | ||||
|     try { | ||||
|       String cmd = "chmod 777 " + pkgCodePath; | ||||
|       process = Runtime.getRuntime().exec("su"); //切换到root帐号
 | ||||
|       os = new DataOutputStream(process.getOutputStream()); | ||||
|       os.writeBytes(cmd + "\n"); | ||||
|       os.writeBytes("exit\n"); | ||||
|       os.flush(); | ||||
|       return process.waitFor() == 0; | ||||
|     } catch (Exception e) { | ||||
|       return false; | ||||
|     } finally { | ||||
|       try { | ||||
|         if (os != null) { | ||||
|           os.close(); | ||||
|         } | ||||
|         if (process != null) { | ||||
|           process.destroy(); | ||||
|         } | ||||
|       } catch (IOException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取指定包名的包信息 | ||||
|    */ | ||||
|   public static PackageInfo getAppInfo(Context context, String packageName) { | ||||
|     try { | ||||
|       return context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_ACTIVITIES); | ||||
|     } catch (PackageManager.NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|       return null; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取未安装软件包的包名 | ||||
|    */ | ||||
|   public static String getApkPackageName(Context context, String apkPath) { | ||||
|     PackageManager pm = context.getPackageManager(); | ||||
|     PackageInfo info = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES); | ||||
|     if (info != null) { | ||||
|       ApplicationInfo appInfo = info.applicationInfo; | ||||
|       appInfo.sourceDir = apkPath; | ||||
|       appInfo.publicSourceDir = apkPath; | ||||
|       return appInfo.packageName; | ||||
|     } | ||||
|     return ""; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 判断是否安装 | ||||
|    */ | ||||
|   public static boolean apkIsInstall(Context context, String apkPath) { | ||||
|     PackageManager pm = context.getPackageManager(); | ||||
|     PackageInfo info = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES); | ||||
|     if (info != null) { | ||||
|       ApplicationInfo appInfo = info.applicationInfo; | ||||
|       appInfo.sourceDir = apkPath; | ||||
|       appInfo.publicSourceDir = apkPath; | ||||
|       try { | ||||
|         pm.getPackageInfo(appInfo.packageName, PackageManager.GET_UNINSTALLED_PACKAGES); | ||||
|         return true; | ||||
|       } catch (PackageManager.NameNotFoundException localNameNotFoundException) { | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 判断服务是否后台运行 | ||||
|    * | ||||
|    * @param context Context | ||||
|    * @return true 在运行 false 不在运行 | ||||
|    */ | ||||
|   public static boolean isServiceRun(Context context, Class<?> clazz) { | ||||
|     boolean isRun = false; | ||||
|     ActivityManager activityManager = | ||||
|         (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); | ||||
|     List<ActivityManager.RunningServiceInfo> serviceList = | ||||
|         activityManager.getRunningServices(Integer.MAX_VALUE); | ||||
|     int size = serviceList.size(); | ||||
|     for (int i = 0; i < size; i++) { | ||||
|       if (serviceList.get(i).service.getClassName().equals(clazz.getName())) { | ||||
|         isRun = true; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     return isRun; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 启动另外一个App | ||||
|    */ | ||||
|   public static void startOtherApp(Context context, String packageName) { | ||||
|     PackageManager pm = context.getPackageManager(); | ||||
|     Intent launcherIntent = pm.getLaunchIntentForPackage(packageName); | ||||
|     launcherIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|     //launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
 | ||||
|     context.startActivity(launcherIntent); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 判断手机是否拥有Root权限。 | ||||
|    * | ||||
|    * @return 有root权限返回true,否则返回false。 | ||||
|    */ | ||||
|   public static boolean isRoot() { | ||||
|     String binPath = "/system/bin/su"; | ||||
|     String xBinPath = "/system/xbin/su"; | ||||
|     return new File(binPath).exists() && isExecutable(binPath) | ||||
|         || new File(xBinPath).exists() && isExecutable(xBinPath); | ||||
|   } | ||||
| 
 | ||||
|   private static boolean isExecutable(String filePath) { | ||||
|     Process p = null; | ||||
|     try { | ||||
|       p = Runtime.getRuntime().exec("ls -l " + filePath); | ||||
|       // 获取返回内容
 | ||||
|       BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); | ||||
|       String str = in.readLine(); | ||||
|       L.i(TAG, str); | ||||
|       if (str != null && str.length() >= 4) { | ||||
|         char flag = str.charAt(3); | ||||
|         if (flag == 's' || flag == 'x') return true; | ||||
|       } | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } finally { | ||||
|       if (p != null) { | ||||
|         p.destroy(); | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 静默卸载 | ||||
|    */ | ||||
|   public static boolean uninstallInBackground(String packageName) { | ||||
|     String command = "pm uninstall -k " + packageName + "\n"; | ||||
|     ShellUtils.CommandResult result = ShellUtils.execCommand(command, true); | ||||
|     String errorMsg = result.errorMsg; | ||||
|     L.d(TAG, "error msg = " + result.errorMsg); | ||||
|     L.d(TAG, "success msg = " + result.successMsg); | ||||
|     int res = result.result; | ||||
|     return res == 0 && !errorMsg.contains("Failure"); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 静默安装APk | ||||
|    * 执行具体的静默安装逻辑,需要手机ROOT。 | ||||
|    * | ||||
|    * @param apkPath 要安装的apk文件的路径 | ||||
|    * @return 安装成功返回true,安装失败返回false。 | ||||
|    */ | ||||
|   public static boolean installInBackground(String apkPath) { | ||||
|     String command = "pm install -r " + apkPath + "\n"; | ||||
|     ShellUtils.CommandResult result = ShellUtils.execCommand(command, true); | ||||
|     String errorMsg = result.errorMsg; | ||||
|     L.d(TAG, "error msg = " + result.errorMsg); | ||||
|     L.d(TAG, "success msg = " + result.successMsg); | ||||
|     int res = result.result; | ||||
|     return res == 0 && !errorMsg.contains("Failure"); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取状态栏高度 | ||||
|    */ | ||||
|   public static int getStatusBarHeight(Context context) { | ||||
|     int result = 0; | ||||
|     int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); | ||||
|     if (resourceId > 0) { | ||||
|       result = context.getResources().getDimensionPixelSize(resourceId); | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取导航栏高度 | ||||
|    */ | ||||
|   public static int getNavigationBarHeight(Context context) { | ||||
|     Resources resources = context.getResources(); | ||||
|     int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); | ||||
|     if (resourceId > 0) { | ||||
|       return resources.getDimensionPixelSize(resourceId); | ||||
|     } | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取当前窗口的高度, 该高度是不包含导航栏和状态栏的 | ||||
|    */ | ||||
|   public static int getWindowHeight(Activity activity) { | ||||
|     return activity.getWindow().getWindowManager().getDefaultDisplay().getHeight(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取当前窗口的宽度 | ||||
|    */ | ||||
|   public static int getWindowWidth(Activity activity) { | ||||
|     return activity.getWindow().getWindowManager().getDefaultDisplay().getWidth(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取屏幕参数,这个获取到的高是包含导航栏和状态栏的 | ||||
|    */ | ||||
|   public static int[] getScreenParams(Context context) { | ||||
|     WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); | ||||
|     return new int[] { wm.getDefaultDisplay().getWidth(), wm.getDefaultDisplay().getHeight() }; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 检查手机是否安装了指定的APK | ||||
|    * | ||||
|    * @param packageName 该APK的包名 | ||||
|    */ | ||||
|   public static boolean checkApkExists(Context context, String packageName) { | ||||
|     List<PackageInfo> packageInfos = getAllApps(context); | ||||
|     for (PackageInfo pi : packageInfos) { | ||||
|       if (pi.packageName.equals(packageName)) { | ||||
|         return true; | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 查询手机内所有应用 | ||||
|    */ | ||||
|   public static List<PackageInfo> getAllApps(Context context) { | ||||
|     List<PackageInfo> apps = new ArrayList<PackageInfo>(); | ||||
|     PackageManager pManager = context.getPackageManager(); | ||||
|     //获取手机内所有应用
 | ||||
|     List<PackageInfo> paklist = pManager.getInstalledPackages(0); | ||||
|     for (int i = 0; i < paklist.size(); i++) { | ||||
|       PackageInfo pak = paklist.get(i); | ||||
|       apps.add(pak); | ||||
|     } | ||||
|     return apps; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 查询手机内非系统应用 | ||||
|    */ | ||||
|   public static List<PackageInfo> getAllNoSystemApps(Context context) { | ||||
|     List<PackageInfo> apps = new ArrayList<PackageInfo>(); | ||||
|     PackageManager pManager = context.getPackageManager(); | ||||
|     //获取手机内所有应用
 | ||||
|     List<PackageInfo> paklist = pManager.getInstalledPackages(0); | ||||
|     for (int i = 0; i < paklist.size(); i++) { | ||||
|       PackageInfo pak = paklist.get(i); | ||||
|       //判断是否为非系统预装的应用程序
 | ||||
|       if ((pak.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) { | ||||
|         // customs applications
 | ||||
|         apps.add(pak); | ||||
|       } | ||||
|     } | ||||
|     return apps; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取目录 | ||||
|    */ | ||||
|   public static String getSourcePath(Context context, String packageName) { | ||||
|     ApplicationInfo appInfo = null; | ||||
|     try { | ||||
|       appInfo = context.getPackageManager().getApplicationInfo(packageName, 0); | ||||
|       return appInfo.sourceDir; | ||||
|     } catch (PackageManager.NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取包名 | ||||
|    */ | ||||
|   public static String getPackageName(Context context) { | ||||
|     return getPackageInfo(context).packageName; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取应用名 | ||||
|    */ | ||||
|   public static String getAppName(Context context) { | ||||
|     try { | ||||
|       return context.getString(context.getApplicationInfo().labelRes); | ||||
|     } catch (Resources.NotFoundException e) { | ||||
|       FL.e(TAG, FL.getExceptionString(e)); | ||||
|       return ""; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取设备的唯一ID | ||||
|    */ | ||||
|   public static String getAndroidId(Context context) { | ||||
|     return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回版本名称 | ||||
|    */ | ||||
|   public static String getVersionName(Context context) { | ||||
|     return getPackageInfo(context).versionName; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回版本号 | ||||
|    */ | ||||
|   public static int getVersionCode(Context context) { | ||||
|     return getPackageInfo(context).versionCode; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 打开一个隐藏了图标的APP | ||||
|    */ | ||||
|   public static void openAppWithAction(Context context, String packageName, String activity) { | ||||
|     ComponentName componentName = new ComponentName(packageName, activity); | ||||
|     try { | ||||
|       Intent intent = new Intent(); | ||||
|       intent.setComponent(componentName); | ||||
|       context.startActivity(intent); | ||||
|     } catch (Exception e) { | ||||
|       FL.e(TAG, "没有找到应用程序:packageName:" + packageName + "  activity:" + activity); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 应用是否被安装 | ||||
|    */ | ||||
|   public static boolean isInstall(Context context, String packageName) { | ||||
|     PackageInfo packageInfo = null; | ||||
|     try { | ||||
|       packageInfo = context.getPackageManager().getPackageInfo(packageName, 0); | ||||
|     } catch (PackageManager.NameNotFoundException e) { | ||||
|       //            e.printStackTrace();
 | ||||
|     } | ||||
|     return packageInfo != null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 安装APP | ||||
|    */ | ||||
|   public static void install(Context context, File file) { | ||||
|     L.e(TAG, "install Apk:" + file.getName()); | ||||
|     context.startActivity(getInstallIntent(file)); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 卸载APk | ||||
|    * | ||||
|    * @param packageName 包名 | ||||
|    */ | ||||
|   public static void uninstall(Context context, String packageName) { | ||||
|     Uri packageURI = Uri.parse("package:" + packageName); | ||||
|     Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI); | ||||
|     uninstallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|     context.startActivity(uninstallIntent); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取安装应用的Intent | ||||
|    */ | ||||
|   public static Intent getInstallIntent(File file) { | ||||
|     Intent intent = new Intent(); | ||||
|     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|     intent.setAction(Intent.ACTION_VIEW); | ||||
|     intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); | ||||
|     return intent; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 拷贝Assets中的文件到指定目录 | ||||
|    */ | ||||
|   public static boolean copyFileFromAssets(Context context, String fileName, String path) { | ||||
|     boolean copyIsFinish = false; | ||||
|     try { | ||||
|       InputStream is = context.getAssets().open(fileName); | ||||
|       File file = FileUtil.createFile(path); | ||||
|       FileOutputStream fos = new FileOutputStream(file); | ||||
|       byte[] temp = new byte[1024]; | ||||
|       int i = 0; | ||||
|       while ((i = is.read(temp)) > 0) { | ||||
|         fos.write(temp, 0, i); | ||||
|       } | ||||
|       fos.close(); | ||||
|       is.close(); | ||||
|       copyIsFinish = true; | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return copyIsFinish; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取版本信息 | ||||
|    */ | ||||
|   public static PackageInfo getPackageInfo(Context context) { | ||||
|     PackageInfo pkg = null; | ||||
|     if (context == null) { | ||||
|       return null; | ||||
|     } | ||||
|     try { | ||||
|       pkg = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); | ||||
|     } catch (PackageManager.NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return pkg; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取设备的显示属性 | ||||
|    */ | ||||
|   public static DisplayMetrics getDisplayMetrics(Context context) { | ||||
|     return context.getResources().getDisplayMetrics(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取电话号码 | ||||
|    */ | ||||
|   public static String getLocalPhoneNumber(Context context) { | ||||
|     if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) | ||||
|         != PackageManager.PERMISSION_GRANTED | ||||
|         && ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_NUMBERS) | ||||
|         != PackageManager.PERMISSION_GRANTED | ||||
|         && ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) | ||||
|         != PackageManager.PERMISSION_GRANTED) { | ||||
|       String line1Number = getTelephonyManager(context).getLine1Number(); | ||||
|       return line1Number == null ? "" : line1Number; | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取设备型号(Nexus5) | ||||
|    */ | ||||
|   public static String getDeviceModel() { | ||||
|     return Build.MODEL; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取电话通讯管理(可以通过这个对象获取手机号码等) | ||||
|    */ | ||||
|   public static TelephonyManager getTelephonyManager(Context context) { | ||||
|     return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取版本号 | ||||
|    */ | ||||
|   public static String getSystemVersion() { | ||||
|     // 获取android版本号
 | ||||
|     return Build.VERSION.RELEASE; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回ApplicationInfo(可以通过这个读取meta-data等等) | ||||
|    */ | ||||
|   public static ApplicationInfo getApplicationInfo(Context context) { | ||||
|     if (context == null) { | ||||
|       return null; | ||||
|     } | ||||
|     ApplicationInfo applicationInfo = null; | ||||
|     try { | ||||
|       applicationInfo = context.getPackageManager() | ||||
|           .getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); | ||||
|     } catch (PackageManager.NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return applicationInfo; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取MetaData的Bundle | ||||
|    */ | ||||
|   public static Bundle getMetaData(Context context) { | ||||
|     ApplicationInfo applicationInfo = getApplicationInfo(context); | ||||
|     if (applicationInfo == null) { | ||||
|       return new Bundle(); | ||||
|     } | ||||
|     return applicationInfo.metaData; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 应用是否启动 | ||||
|    */ | ||||
|   public static boolean appIsRunning(Context context) { | ||||
|     boolean isAppRunning = false; | ||||
|     ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); | ||||
|     List<ActivityManager.RunningTaskInfo> list = am.getRunningTasks(100); | ||||
|     String packageName = getPackageInfo(context).packageName; | ||||
|     for (ActivityManager.RunningTaskInfo info : list) { | ||||
|       if (info.topActivity.getPackageName().equals(packageName) | ||||
|           && info.baseActivity.getPackageName().equals(packageName)) { | ||||
|         isAppRunning = true; | ||||
|         //find it, break
 | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     return isAppRunning; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 检查系统是否有这个Intent,在启动Intent的时候需要检查,因为启动一个没有的Intent程序会Crash | ||||
|    */ | ||||
|   public static boolean isIntentSafe(Context context, Intent intent) { | ||||
|     PackageManager packageManager = context.getPackageManager(); | ||||
|     List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0); | ||||
|     return activities.size() > 0; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取当前包的系统缓存目录 | ||||
|    * "/Android/data/" + context.getPackageName() + "/cache" | ||||
|    */ | ||||
|   public static String getDiskCacheDir(Context context) { | ||||
|     // Check if media is mounted or storage is built-in, if so, try and use external cache dir
 | ||||
|     // otherwise use internal cache dir
 | ||||
|     File cacheDirPath = getExternalCacheDir(context); | ||||
|     if (cacheDirPath == null) { | ||||
|       cacheDirPath = context.getCacheDir(); | ||||
|     } | ||||
|     return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) | ||||
|         || !isExternalStorageRemovable() ? cacheDirPath.getPath() : context.getCacheDir().getPath(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取当前包的外置路径 | ||||
|    * "/Android/data/" + context.getPackageName() | ||||
|    */ | ||||
|   public static String getDiskPackage(Context context) { | ||||
|     return new File(getDiskCacheDir(context)).getParent(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Check if external storage is built-in or removable. | ||||
|    * | ||||
|    * @return True if external storage is removable (like an SD card), false | ||||
|    * otherwise. | ||||
|    */ | ||||
|   @TargetApi(Build.VERSION_CODES.GINGERBREAD) public static boolean isExternalStorageRemovable() { | ||||
|     return !AndroidVersionUtil.hasGingerbread() || Environment.isExternalStorageRemovable(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Get the external app cache directory. | ||||
|    * | ||||
|    * @param context The context to use | ||||
|    * @return The external cache dir | ||||
|    */ | ||||
|   @TargetApi(Build.VERSION_CODES.FROYO) public static File getExternalCacheDir(Context context) { | ||||
|     if (AndroidVersionUtil.hasFroyo()) { | ||||
|       File cacheDir; | ||||
|       if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) | ||||
|           || !Environment.isExternalStorageRemovable()) { | ||||
|         // /sdcard/Android/data/<application package>/cache
 | ||||
|         if (context == null) { | ||||
|           NullPointerException ex = new NullPointerException("context == null"); | ||||
|           FL.e(TAG, FL.getExceptionString(ex)); | ||||
|           throw ex; | ||||
|         } | ||||
|         cacheDir = context.getExternalCacheDir(); | ||||
|       } else { | ||||
|         // /data/data/<application package>/cache
 | ||||
|         cacheDir = context.getCacheDir(); | ||||
|       } | ||||
|       return cacheDir; | ||||
|     } | ||||
| 
 | ||||
|     // Before Froyo we need to construct the external cache dir ourselves
 | ||||
|     final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/"; | ||||
|     return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Check how much usable space is available at a given path. | ||||
|    * | ||||
|    * @param path The path to check | ||||
|    * @return The space available in bytes | ||||
|    */ | ||||
|   @TargetApi(Build.VERSION_CODES.GINGERBREAD) public static long getUsableSpace(File path) { | ||||
|     if (AndroidVersionUtil.hasGingerbread()) { | ||||
|       return path.getUsableSpace(); | ||||
|     } | ||||
|     final StatFs stats = new StatFs(path.getPath()); | ||||
|     return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks(); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,90 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.os.Build; | ||||
| 
 | ||||
| /** | ||||
|  * android版本检测工具 | ||||
|  * | ||||
|  * @author lyy | ||||
|  */ | ||||
| public class AndroidVersionUtil { | ||||
|   private AndroidVersionUtil() { | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 当前Android系统版本是否在( Donut) Android 1.6或以上 | ||||
|    */ | ||||
|   public static boolean hasDonut() { | ||||
|     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.DONUT; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 当前Android系统版本是否在( Eclair) Android 2.0或 以上 | ||||
|    */ | ||||
|   public static boolean hasEclair() { | ||||
|     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 当前Android系统版本是否在( Froyo) Android 2.2或 Android 2.2以上 | ||||
|    */ | ||||
|   public static boolean hasFroyo() { | ||||
|     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 当前Android系统版本是否在( Gingerbread) Android 2.3x或 Android 2.3x 以上 | ||||
|    */ | ||||
|   public static boolean hasGingerbread() { | ||||
|     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 当前Android系统版本是否在( Honeycomb) Android3.1或 Android3.1以上 | ||||
|    */ | ||||
|   public static boolean hasHoneycomb() { | ||||
|     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 当前Android系统版本是否在( HoneycombMR1) Android3.1.1或 Android3.1.1以上 | ||||
|    */ | ||||
|   public static boolean hasHoneycombMR1() { | ||||
|     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 当前Android系统版本是否在( IceCreamSandwich) Android4.0或 Android4.0以上 | ||||
|    */ | ||||
|   public static boolean hasIcecreamsandwich() { | ||||
|     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 当前android系统版本是否在(JellyBean)Android4.1或android4.1以上 | ||||
|    */ | ||||
|   public static boolean hasJellyBean() { | ||||
|     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 当前android系统版本是否在(KitKat)Android4.4或android4.4以上 | ||||
|    */ | ||||
|   public static boolean hasKitKat() { | ||||
|     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 当前是否在5.0以上 | ||||
|    */ | ||||
|   public static boolean hasLollipop() { | ||||
|     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 当前是否在6.0以上 | ||||
|    */ | ||||
|   public static boolean hasM() { | ||||
|     return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,82 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.pm.PackageInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.content.pm.Signature; | ||||
| 
 | ||||
| import java.security.MessageDigest; | ||||
| import java.security.NoSuchAlgorithmException; | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| /** | ||||
|  * 应用签名信息 | ||||
|  * Created by YangQiang on 2014/11/27. | ||||
|  */ | ||||
| public class AppSigning { | ||||
|   public final static String MD5 = "MD5"; | ||||
|   public final static String SHA1 = "SHA1"; | ||||
|   public final static String SHA256 = "SHA256"; | ||||
| 
 | ||||
|   /** | ||||
|    * 返回一个签名的对应类型的字符串 | ||||
|    */ | ||||
|   public static ArrayList<String> getSingInfo(Context context, String packageName, String type) { | ||||
|     ArrayList<String> result = new ArrayList<String>(); | ||||
|     try { | ||||
|       Signature[] signs = getSignatures(context, packageName); | ||||
|       for (Signature sig : signs) { | ||||
|         String tmp = "error!"; | ||||
|         if (MD5.equals(type)) { | ||||
|           tmp = getSignatureString(sig, MD5); | ||||
|         } else if (SHA1.equals(type)) { | ||||
|           tmp = getSignatureString(sig, SHA1); | ||||
|         } else if (SHA256.equals(type)) { | ||||
|           tmp = getSignatureString(sig, SHA256); | ||||
|         } | ||||
|         result.add(tmp); | ||||
|       } | ||||
|     } catch (Exception e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回对应包的签名信息 | ||||
|    */ | ||||
|   public static Signature[] getSignatures(Context context, String packageName) { | ||||
|     PackageInfo packageInfo = null; | ||||
|     try { | ||||
|       packageInfo = | ||||
|           context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES); | ||||
|       return packageInfo.signatures; | ||||
|     } catch (PackageManager.NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取相应的类型的字符串(把签名的byte[]信息转换成16进制) | ||||
|    */ | ||||
|   public static String getSignatureString(Signature sig, String type) { | ||||
|     byte[] hexBytes = sig.toByteArray(); | ||||
|     String fingerprint = "error!"; | ||||
|     try { | ||||
|       MessageDigest digest = MessageDigest.getInstance(type); | ||||
|       if (digest != null) { | ||||
|         byte[] digestBytes = digest.digest(hexBytes); | ||||
|         StringBuilder sb = new StringBuilder(); | ||||
|         for (byte digestByte : digestBytes) { | ||||
|           sb.append((Integer.toHexString((digestByte & 0xFF) | 0x100)).substring(1, 3)); | ||||
|         } | ||||
|         fingerprint = sb.toString(); | ||||
|       } | ||||
|     } catch (NoSuchAlgorithmException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
| 
 | ||||
|     return fingerprint; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,135 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.pm.PackageInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.content.pm.PackageManager.NameNotFoundException; | ||||
| import android.content.pm.Signature; | ||||
| 
 | ||||
| import java.security.MessageDigest; | ||||
| import java.security.NoSuchAlgorithmException; | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| /** | ||||
|  * 跟App相关的辅助类 | ||||
|  */ | ||||
| public class AppUtils { | ||||
|   /** | ||||
|    * 应用签名信息 | ||||
|    */ | ||||
|   public final static String MD5 = "MD5"; | ||||
|   public final static String SHA1 = "SHA1"; | ||||
|   public final static String SHA256 = "SHA256"; | ||||
| 
 | ||||
|   /** | ||||
|    * 返回一个签名的对应类型的字符串 | ||||
|    */ | ||||
|   public static ArrayList<String> getSingInfo(Context context, String packageName, String type) { | ||||
|     ArrayList<String> result = new ArrayList<String>(); | ||||
|     try { | ||||
|       Signature[] signs = getSignatures(context, packageName); | ||||
|       for (Signature sig : signs) { | ||||
|         String tmp = "error!"; | ||||
|         if (MD5.equals(type)) { | ||||
|           tmp = getSignatureString(sig, MD5); | ||||
|         } else if (SHA1.equals(type)) { | ||||
|           tmp = getSignatureString(sig, SHA1); | ||||
|         } else if (SHA256.equals(type)) { | ||||
|           tmp = getSignatureString(sig, SHA256); | ||||
|         } | ||||
|         result.add(tmp); | ||||
|       } | ||||
|     } catch (Exception e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回对应包的签名信息 | ||||
|    */ | ||||
|   public static Signature[] getSignatures(Context context, String packageName) { | ||||
|     PackageInfo packageInfo = null; | ||||
|     try { | ||||
|       packageInfo = | ||||
|           context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES); | ||||
|       return packageInfo.signatures; | ||||
|     } catch (NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取相应的类型的字符串(把签名的byte[]信息转换成16进制) | ||||
|    */ | ||||
|   public static String getSignatureString(Signature sig, String type) { | ||||
|     byte[] hexBytes = sig.toByteArray(); | ||||
|     String fingerprint = "error!"; | ||||
|     try { | ||||
|       MessageDigest digest = MessageDigest.getInstance(type); | ||||
|       if (digest != null) { | ||||
|         byte[] digestBytes = digest.digest(hexBytes); | ||||
|         StringBuilder sb = new StringBuilder(); | ||||
|         for (byte digestByte : digestBytes) { | ||||
|           sb.append((Integer.toHexString((digestByte & 0xFF) | 0x100)).substring(1, 3)); | ||||
|         } | ||||
|         fingerprint = sb.toString(); | ||||
|       } | ||||
|     } catch (NoSuchAlgorithmException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
| 
 | ||||
|     return fingerprint; | ||||
|   } | ||||
| 
 | ||||
|   private AppUtils() { | ||||
|     throw new UnsupportedOperationException("cannot be instantiated"); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取应用程序名称 | ||||
|    */ | ||||
|   public static String getAppName(Context context) { | ||||
|     try { | ||||
|       PackageManager packageManager = context.getPackageManager(); | ||||
|       PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); | ||||
|       int labelRes = packageInfo.applicationInfo.labelRes; | ||||
|       return context.getResources().getString(labelRes); | ||||
|     } catch (NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * [获取应用程序版本名称信息] | ||||
|    * | ||||
|    * @return 当前应用的版本名称 | ||||
|    */ | ||||
|   public static String getVersionName(Context context) { | ||||
|     try { | ||||
|       PackageManager packageManager = context.getPackageManager(); | ||||
|       PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); | ||||
|       return packageInfo.versionName; | ||||
|     } catch (NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取应用版本号 | ||||
|    * | ||||
|    * @return 当前应用版本 | ||||
|    */ | ||||
|   public static int getVersionNumber(Context context) { | ||||
|     try { | ||||
|       PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); | ||||
|       return info.versionCode; | ||||
|     } catch (NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return 1; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,299 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import com.arialyy.frame.util.show.FL; | ||||
| 
 | ||||
| import java.text.ParseException; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.Calendar; | ||||
| import java.util.Date; | ||||
| 
 | ||||
| /** | ||||
|  * 日历工具类 Create by lyy on 13-7-8. | ||||
|  */ | ||||
| public class CalendarUtils { | ||||
|   private static final String TAG = "CalendarUtils"; | ||||
|   /** | ||||
|    * 完整的日期时间格式 | ||||
|    */ | ||||
|   public final static String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; | ||||
|   /** | ||||
|    * 只有日期的格式 | ||||
|    */ | ||||
|   public final static String DATE_FORMAT = "yyyy-MM-dd"; | ||||
|   /** | ||||
|    * 只有时间的格式 | ||||
|    */ | ||||
|   public final static String TIME_FORMAT = "HH:mm:ss"; | ||||
|   /** | ||||
|    * 带中文的日期格式(2000年01月01日) | ||||
|    */ | ||||
|   public final static String DATE_FORMAT_WITH_CHINESE = "yyyy年MM月dd日"; | ||||
|   /** | ||||
|    * 短时间格式(HH:mm) | ||||
|    */ | ||||
|   public final static String SHORT_TIME_FORMAT = "HH:mm"; | ||||
| 
 | ||||
|   /** | ||||
|    * 私有构造 | ||||
|    */ | ||||
|   private CalendarUtils() { | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 把String类型的日期转换成Calendar对象 | ||||
|    * | ||||
|    * @param string (日期时间:2000-00-00 00:00:00) | ||||
|    */ | ||||
|   public static Calendar transformStringToCalendar(String string) { | ||||
|     return transformStringToCalendar(string, DATE_TIME_FORMAT); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 通过SimpleDataFormat格式把string转换成Calendar | ||||
|    * | ||||
|    * @param string 日期字符串 | ||||
|    * @param format 目标日期格式 | ||||
|    */ | ||||
|   public static Calendar transformStringToCalendar(String string, String format) { | ||||
|     SimpleDateFormat sdf = new SimpleDateFormat(format); | ||||
|     Date date = null; | ||||
|     try { | ||||
|       date = sdf.parse(string); | ||||
|     } catch (ParseException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     Calendar calendar = Calendar.getInstance(); | ||||
|     calendar.setTime(date); | ||||
|     return calendar; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 把日期字符串转换成TimeMillis | ||||
|    */ | ||||
|   public static long transformStringToMillis(String string) { | ||||
|     return transformStringToCalendar(string).getTimeInMillis(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 通过TimeMillis转换成秒钟 | ||||
|    * | ||||
|    * @param millis TimeMillis | ||||
|    */ | ||||
|   public static long getSecondWithTimeMillis(long millis) { | ||||
|     return millis / 1000; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回两个日期相差的秒 | ||||
|    */ | ||||
|   public static long getIntervalInSeconds(Calendar calendar, Calendar targetCalendar) { | ||||
|     return (calendar.getTimeInMillis() - targetCalendar.getTimeInMillis()) / 1000; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化日期 | ||||
|    * | ||||
|    * @param string 有效的日期字符 | ||||
|    * @param format 格式化的格式 | ||||
|    */ | ||||
|   public static String formatWithString(String string, String format) { | ||||
|     SimpleDateFormat sdf = new SimpleDateFormat(format); | ||||
|     return sdf.format(transformStringToCalendar(string).getTime()); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化日期 | ||||
|    * | ||||
|    * @param src 源日期字符 | ||||
|    * @param srcFormat 源日期格式 | ||||
|    * @param targetFormat 目标日期格式 | ||||
|    */ | ||||
|   public static String formatWithString(String src, String srcFormat, String targetFormat) { | ||||
|     SimpleDateFormat sdf = new SimpleDateFormat(srcFormat); | ||||
|     try { | ||||
|       Date date = sdf.parse(src); | ||||
|       SimpleDateFormat targetSdf = new SimpleDateFormat(targetFormat); | ||||
|       return targetSdf.format(date); | ||||
|     } catch (Exception e) { | ||||
|       FL.e(TAG, "src=" + src + "  " + srcFormat + "  " + targetFormat); | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化成日期时间 | ||||
|    * | ||||
|    * @param string 将要被格式化的日期字符串 | ||||
|    * @return 格式:(2000-00-00 00:00:00) | ||||
|    */ | ||||
|   public static String formatDateTimeWithString(String string) { | ||||
|     return formatWithString(string, DATE_TIME_FORMAT); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化日期 | ||||
|    * | ||||
|    * @param srcDate 源日期字符 | ||||
|    * @param srcDateFormat 源日期格式 | ||||
|    * @param targetFormat 目标格式 | ||||
|    */ | ||||
|   public static String formatDateTimeWithString(String srcDate, String srcDateFormat, | ||||
|       String targetFormat) { | ||||
|     SimpleDateFormat sdf = new SimpleDateFormat(srcDateFormat); | ||||
|     try { | ||||
|       Date date = sdf.parse(srcDate); | ||||
|       SimpleDateFormat parseSdf = new SimpleDateFormat(targetFormat); | ||||
|       return parseSdf.format(date); | ||||
|     } catch (ParseException e) { | ||||
|       FL.e(TAG, "srcDate:" | ||||
|           + srcDate | ||||
|           + "  srcDateFormat:" | ||||
|           + srcDateFormat | ||||
|           + "   targetFormat" | ||||
|           + targetFormat); | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化日期 | ||||
|    * | ||||
|    * @param string 将要被格式化的日期字符串 | ||||
|    * @return 格式:(2000-00-00) | ||||
|    */ | ||||
|   public static String formatDateWithString(String string) { | ||||
|     return formatWithString(string, DATE_FORMAT); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化日期 | ||||
|    * | ||||
|    * @param string 将要被格式化的日期字符串 | ||||
|    * @return 格式:(00:00:00) | ||||
|    */ | ||||
|   public static String formatTimeWithString(String string) { | ||||
|     return formatWithString(string, TIME_FORMAT); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化日期 | ||||
|    * | ||||
|    * @param string 将要被格式化的日期字符串 | ||||
|    * @return 格式:(2000年01月01日) | ||||
|    */ | ||||
|   public static String formatStringToChinese(String string) { | ||||
|     return formatWithString(string, DATE_FORMAT_WITH_CHINESE); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Data日期格式化成String | ||||
|    * | ||||
|    * @param date 将要被格式化的data | ||||
|    * @return 格式:(2000-00-00 00:00:00) | ||||
|    */ | ||||
|   public static String formatDateTimeWithDate(Date date) { | ||||
|     return formatStringWithDate(date, DATE_TIME_FORMAT); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 时间戳格式的数据格式化成需要的格式 | ||||
|    * | ||||
|    * @param string 将要被格式化的时间戳 | ||||
|    * @return 格式:(2000-00-00 00:00:00) | ||||
|    */ | ||||
|   public static String formatDateTimeWithTime(String string) { | ||||
|     return formatStringWithDate(timeToData(string), DATE_TIME_FORMAT); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 把中文日期(2000年01月01日)格式化成标准日期(2000-01-01) | ||||
|    * | ||||
|    * @param data 将要格式化的日期字符串 | ||||
|    * @return 格式:(2000-00-00); | ||||
|    */ | ||||
|   public static String formatChineseDataToData(String data) { | ||||
|     data = data.replace("年", "-"); | ||||
|     data = data.replace("月", "-"); | ||||
|     data = data.replace("日", ""); | ||||
|     return data; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 日期格式化成String | ||||
|    * | ||||
|    * @param date 将要格式化的日期字符串 | ||||
|    * @return 格式:(format格式) | ||||
|    */ | ||||
|   public static String formatStringWithDate(Date date, String format) { | ||||
|     SimpleDateFormat sdf = new SimpleDateFormat(format); | ||||
|     return sdf.format(date); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 把String类型的时间转换成Calendar | ||||
|    * | ||||
|    * @param time 时间格式:00:00:00 | ||||
|    */ | ||||
|   public static Calendar transformStringTimeToCalendar(String time) { | ||||
|     Calendar calendar = Calendar.getInstance(); | ||||
|     String[] split = time.split(":"); | ||||
|     if (split.length > 0) { | ||||
|       calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(split[0])); | ||||
|     } | ||||
|     if (split.length > 1) { | ||||
|       calendar.set(Calendar.MINUTE, Integer.parseInt(split[1])); | ||||
|     } | ||||
|     if (split.length > 2) { | ||||
|       calendar.set(Calendar.SECOND, Integer.parseInt(split[2])); | ||||
|     } | ||||
|     return calendar; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 把时间戳:1234567890123,转换成Date对象 | ||||
|    */ | ||||
|   public static Date timeToData(String time) { | ||||
|     return new Date(Long.parseLong(time)); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 比较两个字符串日期的大小 | ||||
|    * | ||||
|    * @return 小于0:srcData 小于 tagData; | ||||
|    * 等于0:则srcData = tagData; | ||||
|    * 大于0:则srcData 大余 tagData | ||||
|    */ | ||||
|   public static int compare(String srcDate, String tagDate) { | ||||
|     return srcDate.compareTo(tagDate); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回现在的日期和时间 | ||||
|    * | ||||
|    * @return 格式:2000-00-00 00:00:00 | ||||
|    */ | ||||
|   public static String getNowDataTime() { | ||||
|     Calendar calendar = Calendar.getInstance(); | ||||
|     return formatDateTimeWithDate(calendar.getTime()); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回当前的日期 | ||||
|    * | ||||
|    * @return 格式:2000-00-00 | ||||
|    */ | ||||
|   public static String getData() { | ||||
|     return getNowDataTime().split(" ")[0]; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回当前时间 | ||||
|    * | ||||
|    * @return 格式:00:00:00 | ||||
|    */ | ||||
|   public static String getTime() { | ||||
|     return getNowDataTime().split(" ")[1]; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,55 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.res.Resources; | ||||
| import android.util.TypedValue; | ||||
| 
 | ||||
| /** | ||||
|  * 常用单位转换的辅助类 | ||||
|  */ | ||||
| public class DensityUtils { | ||||
|   private DensityUtils() { | ||||
|         /* cannot be instantiated */ | ||||
|     throw new UnsupportedOperationException("cannot be instantiated"); | ||||
|   } | ||||
| 
 | ||||
|   private static final float DENSITY = Resources.getSystem().getDisplayMetrics().density; | ||||
| 
 | ||||
|   /** | ||||
|    * 另外一种dp转PX方法 | ||||
|    */ | ||||
|   public static int dp2px(int dp) { | ||||
|     return Math.round(dp * DENSITY); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * dp转px | ||||
|    */ | ||||
|   public static int dp2px(Context context, float dpVal) { | ||||
|     return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, | ||||
|         context.getResources().getDisplayMetrics()); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * sp转px | ||||
|    */ | ||||
|   public static int sp2px(Context context, float spVal) { | ||||
|     return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, | ||||
|         context.getResources().getDisplayMetrics()); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * px转dp | ||||
|    */ | ||||
|   public static float px2dp(Context context, float pxVal) { | ||||
|     final float scale = context.getResources().getDisplayMetrics().density; | ||||
|     return (pxVal / scale); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * px转sp | ||||
|    */ | ||||
|   public static float px2sp(Context context, float pxVal) { | ||||
|     return (pxVal / context.getResources().getDisplayMetrics().scaledDensity); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,88 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.BitmapFactory; | ||||
| import android.graphics.Canvas; | ||||
| import android.graphics.Matrix; | ||||
| import android.graphics.PixelFormat; | ||||
| import android.graphics.drawable.BitmapDrawable; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.view.View; | ||||
| 
 | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| public class DrawableUtil { | ||||
| 
 | ||||
|   /** | ||||
|    * View 转换为bitmap | ||||
|    */ | ||||
|   public static Bitmap convertViewToBitmap(View v) { | ||||
|     v.setDrawingCacheEnabled(true); | ||||
|     v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), | ||||
|         View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); | ||||
|     v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); | ||||
| 
 | ||||
|     v.buildDrawingCache(true); | ||||
|     Bitmap b = Bitmap.createBitmap(v.getDrawingCache()); | ||||
|     v.setDrawingCacheEnabled(false); // clear drawing cache
 | ||||
|     return b; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 收缩图片 | ||||
|    */ | ||||
|   public static Drawable zoomDrawable(Drawable drawable, int w, int h) { | ||||
|     int width = drawable.getIntrinsicWidth(); | ||||
|     int height = drawable.getIntrinsicHeight(); | ||||
|     Bitmap oldbmp = drawableToBitmap(drawable); | ||||
|     Matrix matrix = new Matrix(); | ||||
|     float scaleWidth = ((float) w / width); | ||||
|     float scaleHeight = ((float) h / height); | ||||
|     matrix.postScale(scaleWidth, scaleHeight); | ||||
|     Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height, matrix, true); | ||||
|     return new BitmapDrawable(null, newbmp); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * drawable转bitMap | ||||
|    */ | ||||
|   public static Bitmap drawableToBitmap(Drawable drawable) { | ||||
|     int width = drawable.getIntrinsicWidth(); | ||||
|     int height = drawable.getIntrinsicHeight(); | ||||
|     Bitmap bitmap = Bitmap.createBitmap(width, height, | ||||
|         drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 | ||||
|             : Bitmap.Config.RGB_565); | ||||
|     Canvas canvas = new Canvas(bitmap); | ||||
|     drawable.setBounds(0, 0, width, height); | ||||
|     drawable.draw(canvas); | ||||
|     return bitmap; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * BitMap2Byte | ||||
|    */ | ||||
|   public static byte[] getBitmapByte(Bitmap bitmap) { | ||||
|     ByteArrayOutputStream out = new ByteArrayOutputStream(); | ||||
|     bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); | ||||
|     try { | ||||
|       out.flush(); | ||||
|       out.close(); | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return out.toByteArray(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Byte2BitMap | ||||
|    */ | ||||
|   public static Bitmap getBitmapFromByte(byte[] temp) { | ||||
|     if (temp != null) { | ||||
|       Bitmap bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length); | ||||
|       return bitmap; | ||||
|     } else { | ||||
|       return null; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,520 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.pm.ApplicationInfo; | ||||
| import android.content.pm.PackageInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| import com.arialyy.frame.util.show.FL; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| 
 | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.BufferedOutputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.ObjectInputStream; | ||||
| import java.io.ObjectOutputStream; | ||||
| import java.io.OutputStream; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.math.BigDecimal; | ||||
| import java.math.BigInteger; | ||||
| import java.security.MessageDigest; | ||||
| import java.security.NoSuchAlgorithmException; | ||||
| import java.util.Enumeration; | ||||
| import java.util.zip.ZipEntry; | ||||
| import java.util.zip.ZipFile; | ||||
| 
 | ||||
| /** | ||||
|  * 文件操作工具 可以创建和删除文件等 | ||||
|  */ | ||||
| public class FileUtil { | ||||
|   private static final String KB = "KB"; | ||||
|   private static final String MB = "MB"; | ||||
|   private static final String GB = "GB"; | ||||
| 
 | ||||
|   private FileUtil() { | ||||
|   } | ||||
| 
 | ||||
|   private static final String TAG = "FileUtil"; | ||||
| 
 | ||||
|   /** | ||||
|    * 获取文件夹大小 | ||||
|    */ | ||||
|   public static long getDirSize(String filePath) { | ||||
|     long size = 0; | ||||
|     File f = new File(filePath); | ||||
|     if (f.isDirectory()) { | ||||
|       File[] files = f.listFiles(); | ||||
|       for (File file : files) { | ||||
|         if (file.isDirectory()) { | ||||
|           size += getDirSize(file.getPath()); | ||||
|           continue; | ||||
|         } | ||||
|         size += file.length(); | ||||
|       } | ||||
|     } else { | ||||
|       size += f.length(); | ||||
|     } | ||||
|     return size; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 存储bitmap | ||||
|    */ | ||||
|   public static void saveBitmap(@NonNull String filePath, @NonNull Bitmap bitmap) { | ||||
|     File file = createFile(filePath); | ||||
|     try { | ||||
|       FileOutputStream os = new FileOutputStream(file); | ||||
|       bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os); | ||||
|       os.flush(); | ||||
|       os.close(); | ||||
|     } catch (FileNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化文件大小 | ||||
|    * | ||||
|    * @param size file.length() 获取文件大小 | ||||
|    */ | ||||
|   public static String formatFileSize(double size) { | ||||
|     double kiloByte = size / 1024; | ||||
|     if (kiloByte < 1) { | ||||
|       return size + "B"; | ||||
|     } | ||||
| 
 | ||||
|     double megaByte = kiloByte / 1024; | ||||
|     if (megaByte < 1) { | ||||
|       BigDecimal result1 = new BigDecimal(Double.toString(kiloByte)); | ||||
|       return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB"; | ||||
|     } | ||||
| 
 | ||||
|     double gigaByte = megaByte / 1024; | ||||
|     if (gigaByte < 1) { | ||||
|       BigDecimal result2 = new BigDecimal(Double.toString(megaByte)); | ||||
|       return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB"; | ||||
|     } | ||||
| 
 | ||||
|     double teraBytes = gigaByte / 1024; | ||||
|     if (teraBytes < 1) { | ||||
|       BigDecimal result3 = new BigDecimal(Double.toString(gigaByte)); | ||||
|       return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB"; | ||||
|     } | ||||
|     BigDecimal result4 = new BigDecimal(teraBytes); | ||||
|     return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB"; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取文件后缀名 | ||||
|    */ | ||||
|   public static String getFileExtensionName(String fileName) { | ||||
|     if (TextUtils.isEmpty(fileName)) { | ||||
|       return ""; | ||||
|     } | ||||
|     int endP = fileName.lastIndexOf("."); | ||||
|     return endP > -1 ? fileName.substring(endP + 1, fileName.length()) : ""; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 校验文件MD5码 | ||||
|    */ | ||||
|   public static boolean checkMD5(String md5, File updateFile) { | ||||
|     if (TextUtils.isEmpty(md5) || updateFile == null) { | ||||
|       L.e(TAG, "MD5 string empty or updateFile null"); | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     String calculatedDigest = getFileMD5(updateFile); | ||||
|     if (calculatedDigest == null) { | ||||
|       L.e(TAG, "calculatedDigest null"); | ||||
|       return false; | ||||
|     } | ||||
|     return calculatedDigest.equalsIgnoreCase(md5); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取文件MD5码 | ||||
|    */ | ||||
|   public static String getFileMD5(File updateFile) { | ||||
|     MessageDigest digest; | ||||
|     try { | ||||
|       digest = MessageDigest.getInstance("MD5"); | ||||
|     } catch (NoSuchAlgorithmException e) { | ||||
|       L.e(TAG, "Exception while getting digest", e); | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     InputStream is; | ||||
|     try { | ||||
|       is = new FileInputStream(updateFile); | ||||
|     } catch (FileNotFoundException e) { | ||||
|       L.e(TAG, "Exception while getting FileInputStream", e); | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     byte[] buffer = new byte[8192]; | ||||
|     int read; | ||||
|     try { | ||||
|       while ((read = is.read(buffer)) > 0) { | ||||
|         digest.update(buffer, 0, read); | ||||
|       } | ||||
|       byte[] md5sum = digest.digest(); | ||||
|       BigInteger bigInt = new BigInteger(1, md5sum); | ||||
|       String output = bigInt.toString(16); | ||||
|       // Fill to 32 chars
 | ||||
|       output = String.format("%32s", output).replace(' ', '0'); | ||||
|       return output; | ||||
|     } catch (IOException e) { | ||||
|       throw new RuntimeException("Unable to process file for MD5", e); | ||||
|     } finally { | ||||
|       try { | ||||
|         is.close(); | ||||
|       } catch (IOException e) { | ||||
|         L.e(TAG, "Exception on closing MD5 input stream", e); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 解压缩功能. | ||||
|    * 将ZIP_FILENAME文件解压到ZIP_DIR目录下. | ||||
|    * | ||||
|    * @param zipFile 压缩文件 | ||||
|    * @param folderPath 解压目录 | ||||
|    */ | ||||
|   public static int unZipFile(File zipFile, String folderPath) { | ||||
|     ZipFile zfile = null; | ||||
|     try { | ||||
|       zfile = new ZipFile(zipFile); | ||||
|       Enumeration zList = zfile.entries(); | ||||
|       ZipEntry ze = null; | ||||
|       byte[] buf = new byte[1024]; | ||||
|       while (zList.hasMoreElements()) { | ||||
|         ze = (ZipEntry) zList.nextElement(); | ||||
|         if (ze.isDirectory()) { | ||||
|           //                    L.d(TAG, "ze.getName() = " + ze.getName());
 | ||||
|           String dirstr = folderPath + ze.getName(); | ||||
|           //dirstr.trim();
 | ||||
|           dirstr = new String(dirstr.getBytes("8859_1"), "GB2312"); | ||||
|           //                    L.d(TAG, "str = " + dirstr);
 | ||||
|           File f = new File(dirstr); | ||||
|           f.mkdir(); | ||||
|           continue; | ||||
|         } | ||||
|         //                L.d(TAG, "ze.getName() = " + ze.getName());
 | ||||
|         OutputStream os = new BufferedOutputStream( | ||||
|             new FileOutputStream(getRealFileName(folderPath, ze.getName()))); | ||||
|         InputStream is = new BufferedInputStream(zfile.getInputStream(ze)); | ||||
|         int readLen = 0; | ||||
|         while ((readLen = is.read(buf)) != -1) { | ||||
|           os.write(buf, 0, readLen); | ||||
|         } | ||||
|         is.close(); | ||||
|         os.close(); | ||||
|       } | ||||
|       zfile.close(); | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 给定根目录,返回一个相对路径所对应的实际文件名. | ||||
|    * | ||||
|    * @param baseDir 指定根目录 | ||||
|    * @param absFileName 相对路径名,来自于ZipEntry中的name | ||||
|    * @return java.io.File 实际的文件 | ||||
|    */ | ||||
|   private static File getRealFileName(String baseDir, String absFileName) { | ||||
|     String[] dirs = absFileName.split("/"); | ||||
|     File ret = new File(baseDir); | ||||
|     String substr = null; | ||||
|     if (dirs.length > 1) { | ||||
|       for (int i = 0; i < dirs.length - 1; i++) { | ||||
|         substr = dirs[i]; | ||||
|         try { | ||||
|           //substr.trim();
 | ||||
|           substr = new String(substr.getBytes("8859_1"), "GB2312"); | ||||
|         } catch (UnsupportedEncodingException e) { | ||||
|           e.printStackTrace(); | ||||
|         } | ||||
|         ret = new File(ret, substr); | ||||
|       } | ||||
|       //            L.d("upZipFile", "1ret = " + ret);
 | ||||
|       if (!ret.exists()) ret.mkdirs(); | ||||
|       substr = dirs[dirs.length - 1]; | ||||
|       try { | ||||
|         //substr.trim();
 | ||||
|         substr = new String(substr.getBytes("8859_1"), "GB2312"); | ||||
|         //                L.d("upZipFile", "substr = " + substr);
 | ||||
|       } catch (UnsupportedEncodingException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|       ret = new File(ret, substr); | ||||
|       //            L.d("upZipFile", "2ret = " + ret);
 | ||||
|       return ret; | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 通过流创建文件 | ||||
|    */ | ||||
|   public static void createFileFormInputStream(InputStream is, String path) { | ||||
|     try { | ||||
|       FileOutputStream fos = new FileOutputStream(path); | ||||
|       byte[] buf = new byte[1376]; | ||||
|       while (is.read(buf) > 0) { | ||||
|         fos.write(buf, 0, buf.length); | ||||
|       } | ||||
|       is.close(); | ||||
|       fos.flush(); | ||||
|       fos.close(); | ||||
|     } catch (FileNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从文件读取对象 | ||||
|    */ | ||||
|   public static Object readObj(String path) { | ||||
|     FileInputStream fis = null; | ||||
|     ObjectInputStream ois = null; | ||||
|     try { | ||||
|       fis = new FileInputStream(path); | ||||
|       ois = new ObjectInputStream(fis); | ||||
|       return ois.readObject(); | ||||
|     } catch (FileNotFoundException e) { | ||||
|       FL.e(TAG, FL.getExceptionString(e)); | ||||
|     } catch (IOException e) { | ||||
|       FL.e(TAG, FL.getExceptionString(e)); | ||||
|     } catch (ClassNotFoundException e) { | ||||
|       FL.e(TAG, FL.getExceptionString(e)); | ||||
|     } finally { | ||||
|       try { | ||||
|         if (fis != null) { | ||||
|           fis.close(); | ||||
|         } | ||||
|         if (ois != null) { | ||||
|           ois.close(); | ||||
|         } | ||||
|       } catch (IOException e) { | ||||
|         FL.e(TAG, FL.getExceptionString(e)); | ||||
|       } | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 存储对象到文件,只有实现了Serailiable接口的对象才能被存储 | ||||
|    */ | ||||
|   public static void writeObj(String path, Object object) { | ||||
|     FileOutputStream fos = null; | ||||
|     ObjectOutputStream oos = null; | ||||
|     File file = new File(path); | ||||
|     if (!file.getParentFile().exists()) { | ||||
|       file.mkdirs(); | ||||
|     } | ||||
|     try { | ||||
|       fos = new FileOutputStream(path); | ||||
|       oos = new ObjectOutputStream(fos); | ||||
|       oos.writeObject(object); | ||||
|     } catch (FileNotFoundException e) { | ||||
|       FL.e(TAG, FL.getExceptionString(e)); | ||||
|     } catch (IOException e) { | ||||
|       FL.e(TAG, FL.getExceptionString(e)); | ||||
|     } finally { | ||||
|       try { | ||||
|         if (fos != null) { | ||||
|           fos.close(); | ||||
|         } | ||||
|         if (oos != null) { | ||||
|           oos.close(); | ||||
|         } | ||||
|       } catch (IOException e) { | ||||
|         FL.e(TAG, FL.getExceptionString(e)); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 创建文件 当文件不存在的时候就创建一个文件,否则直接返回文件 | ||||
|    */ | ||||
|   public static File createFile(String path) { | ||||
|     File file = new File(path); | ||||
|     if (!file.getParentFile().exists()) { | ||||
|       FL.d(TAG, "目标文件所在路径不存在,准备创建……"); | ||||
|       if (!createDir(file.getParent())) { | ||||
|         FL.d(TAG, "创建目录文件所在的目录失败!文件路径【" + path + "】"); | ||||
|       } | ||||
|     } | ||||
|     // 创建目标文件
 | ||||
|     try { | ||||
|       if (!file.exists()) { | ||||
|         if (file.createNewFile()) { | ||||
|           FL.d(TAG, "创建文件成功:" + file.getAbsolutePath()); | ||||
|         } | ||||
|         return file; | ||||
|       } else { | ||||
|         return file; | ||||
|       } | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 创建目录 当目录不存在的时候创建文件,否则返回false | ||||
|    */ | ||||
|   public static boolean createDir(String path) { | ||||
|     File file = new File(path); | ||||
|     if (!file.exists()) { | ||||
|       if (!file.mkdirs()) { | ||||
|         FL.d(TAG, "创建失败,请检查路径和是否配置文件权限!"); | ||||
|         return false; | ||||
|       } | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 拷贝文件 | ||||
|    */ | ||||
|   public static boolean copy(String fromPath, String toPath) { | ||||
|     File file = new File(fromPath); | ||||
|     if (!file.exists()) { | ||||
|       return false; | ||||
|     } | ||||
|     createFile(toPath); | ||||
|     return copyFile(fromPath, toPath); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 拷贝文件 | ||||
|    */ | ||||
|   private static boolean copyFile(String fromFile, String toFile) { | ||||
|     InputStream fosfrom = null; | ||||
|     OutputStream fosto = null; | ||||
|     try { | ||||
|       fosfrom = new FileInputStream(fromFile); | ||||
|       fosto = new FileOutputStream(toFile); | ||||
|       byte bt[] = new byte[1024]; | ||||
|       int c; | ||||
|       while ((c = fosfrom.read(bt)) > 0) { | ||||
|         fosto.write(bt, 0, c); | ||||
|       } | ||||
|       return true; | ||||
|     } catch (Exception ex) { | ||||
|       ex.printStackTrace(); | ||||
|       return false; | ||||
|     } finally { | ||||
|       try { | ||||
|         if (fosfrom != null) { | ||||
|           fosfrom.close(); | ||||
|         } | ||||
|         if (fosto != null) { | ||||
|           fosto.close(); | ||||
|         } | ||||
|       } catch (IOException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 删除文件 如果文件存在删除文件,否则返回false | ||||
|    */ | ||||
|   public static boolean deleteFile(String path) { | ||||
|     File file = new File(path); | ||||
|     if (file.exists()) { | ||||
|       file.delete(); | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 递归删除目录下的所有文件及子目录下所有文件 | ||||
|    * | ||||
|    * @param dir 将要删除的文件目录 | ||||
|    * @return 删除成功返回true,否则返回false,如果文件是空,那么永远返回true | ||||
|    */ | ||||
|   public static boolean deleteDir(File dir) { | ||||
|     if (dir == null) { | ||||
|       return true; | ||||
|     } | ||||
|     if (dir.isDirectory()) { | ||||
|       String[] children = dir.list(); | ||||
|       // 递归删除目录中的子目录下
 | ||||
|       for (int i = 0; i < children.length; i++) { | ||||
|         boolean success = deleteDir(new File(dir, children[i])); | ||||
|         if (!success) { | ||||
|           return false; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     // 目录此时为空,可以删除
 | ||||
|     return dir.delete(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 递归返回文件或者目录的大小(单位:KB) | ||||
|    * 不建议使用这个方法,有点坑 | ||||
|    * 可以使用下面的方法:http://blog.csdn.net/loongggdroid/article/details/12304695
 | ||||
|    */ | ||||
|   private static float getSize(String path, Float size) { | ||||
|     File file = new File(path); | ||||
|     if (file.exists()) { | ||||
|       if (file.isDirectory()) { | ||||
|         String[] children = file.list(); | ||||
|         for (int fileIndex = 0; fileIndex < children.length; ++fileIndex) { | ||||
|           float tmpSize = | ||||
|               getSize(file.getPath() + File.separator + children[fileIndex], size) / 1000; | ||||
|           size += tmpSize; | ||||
|         } | ||||
|       } else if (file.isFile()) { | ||||
|         size += file.length(); | ||||
|       } | ||||
|     } | ||||
|     return size; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取apk文件的icon | ||||
|    * | ||||
|    * @param path apk文件路径 | ||||
|    */ | ||||
|   public static Drawable getApkIcon(Context context, String path) { | ||||
|     PackageManager pm = context.getPackageManager(); | ||||
|     PackageInfo info = pm.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES); | ||||
|     if (info != null) { | ||||
|       ApplicationInfo appInfo = info.applicationInfo; | ||||
|       //android有bug,需要下面这两句话来修复才能获取apk图片
 | ||||
|       appInfo.sourceDir = path; | ||||
|       appInfo.publicSourceDir = path; | ||||
|       //			    String packageName = appInfo.packageName;  //得到安装包名称
 | ||||
|       //	            String version=info.versionName;       //得到版本信息
 | ||||
|       return pm.getApplicationIcon(appInfo); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,37 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.view.inputmethod.InputMethodManager; | ||||
| import android.widget.EditText; | ||||
| 
 | ||||
| /** | ||||
|  * 打开或关闭软键盘 | ||||
|  * | ||||
|  * @author zhy | ||||
|  */ | ||||
| public class KeyBoardUtils { | ||||
|   /** | ||||
|    * 打卡软键盘 | ||||
|    * | ||||
|    * @param mEditText 输入框 | ||||
|    * @param mContext 上下文 | ||||
|    */ | ||||
|   public static void openKeybord(EditText mEditText, Context mContext) { | ||||
|     InputMethodManager imm = | ||||
|         (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); | ||||
|     imm.showSoftInput(mEditText, InputMethodManager.RESULT_SHOWN); | ||||
|     imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 关闭软键盘 | ||||
|    * | ||||
|    * @param mEditText 输入框 | ||||
|    * @param mContext 上下文 | ||||
|    */ | ||||
|   public static void closeKeybord(EditText mEditText, Context mContext) { | ||||
|     InputMethodManager imm = | ||||
|         (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); | ||||
|     imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0); | ||||
|   } | ||||
| }   | ||||
| @ -0,0 +1,47 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import java.math.BigDecimal; | ||||
| 
 | ||||
| /** | ||||
|  * Created by AriaLyy on 2015/1/4. | ||||
|  * 精度转换 | ||||
|  */ | ||||
| public class MathUtil { | ||||
| 
 | ||||
|   /** | ||||
|    * http://spiritfrog.iteye.com/blog/602144
 | ||||
|    */ | ||||
|   public class MBigDecimal { | ||||
|     public static final int ROUND_UP = 0; | ||||
|     public static final int ROUND_DOWN = 1; | ||||
|     public static final int ROUND_CEILING = 2; | ||||
|     public static final int ROUND_FLOOR = 3; | ||||
|     public static final int ROUND_HALF_UP = 4; | ||||
|     public static final int ROUND_HALF_DOWN = 5; | ||||
|     public static final int ROUND_HALF_EVEN = 6; | ||||
|     public static final int ROUND_UNNECESSARY = 7; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置精度 | ||||
|    * float/double的精度取值方式分为以下几种: <br> | ||||
|    * java.math.BigDecimal.ROUND_UP <br> | ||||
|    * java.math.BigDecimal.ROUND_DOWN <br> | ||||
|    * java.math.BigDecimal.ROUND_CEILING <br> | ||||
|    * java.math.BigDecimal.ROUND_FLOOR <br> | ||||
|    * java.math.BigDecimal.ROUND_HALF_UP<br> | ||||
|    * java.math.BigDecimal.ROUND_HALF_DOWN <br> | ||||
|    * java.math.BigDecimal.ROUND_HALF_EVEN <br> | ||||
|    * | ||||
|    * @param scale 精度位数(保留的小数位数) | ||||
|    * @param roundingMode 精度取值方式 | ||||
|    * @return 精度计算后的数据 | ||||
|    */ | ||||
|   public static double round(double value, int scale, int roundingMode) { | ||||
|     BigDecimal bd = new BigDecimal(value); | ||||
|     bd = bd.setScale(scale, roundingMode); | ||||
|     double d = bd.doubleValue(); | ||||
|     bd = null; | ||||
|     return d; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,146 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.net.ConnectivityManager; | ||||
| import android.net.NetworkInfo; | ||||
| import android.provider.Settings; | ||||
| import android.telephony.TelephonyManager; | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| /** | ||||
|  * 跟网络相关的工具类 | ||||
|  */ | ||||
| public class NetUtils { | ||||
| 
 | ||||
|   /** | ||||
|    * 没有网络 | ||||
|    */ | ||||
|   public static final int NETWORK_TYPE_INVALID = 0; | ||||
|   /** | ||||
|    * wap网络 | ||||
|    */ | ||||
|   public static final int NETWORK_TYPE_WAP = 1; | ||||
|   /** | ||||
|    * 2G网络 | ||||
|    */ | ||||
|   public static final int NETWORK_TYPE_2G = 2; | ||||
|   /** | ||||
|    * 3G和3G以上网络,或统称为快速网络 | ||||
|    */ | ||||
|   public static final int NETWORK_TYPE_3G = 3; | ||||
|   /** | ||||
|    * wifi网络 | ||||
|    */ | ||||
|   public static final int NETWORK_TYPE_WIFI = 4; | ||||
| 
 | ||||
|   private NetUtils() { | ||||
|         /* cannot be instantiated */ | ||||
|     throw new UnsupportedOperationException("cannot be instantiated"); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 判断网络是否连接 | ||||
|    */ | ||||
|   public static boolean isConnected(Context context) { | ||||
|     ConnectivityManager cm = | ||||
|         (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); | ||||
|     NetworkInfo ni = cm.getActiveNetworkInfo(); | ||||
|     return ni != null && ni.isConnectedOrConnecting(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 判断是否是wifi连接 | ||||
|    */ | ||||
|   public static boolean isWifi(Context context) { | ||||
|     return getNetWorkType(context) == NETWORK_TYPE_WIFI; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取网络状态,wifi,wap,2g,3g. | ||||
|    * | ||||
|    * @param context 上下文 | ||||
|    * @return int 网络状态 {@link #NETWORK_TYPE_2G},{@link #NETWORK_TYPE_3G}, | ||||
|    * {@link #NETWORK_TYPE_INVALID},{@link #NETWORK_TYPE_WAP},{@link #NETWORK_TYPE_WIFI} | ||||
|    */ | ||||
|   public static int getNetWorkType(Context context) { | ||||
|     int netWorkType = -1; | ||||
|     ConnectivityManager manager = | ||||
|         (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); | ||||
|     NetworkInfo networkInfo = manager.getActiveNetworkInfo(); | ||||
|     if (networkInfo != null && networkInfo.isConnected()) { | ||||
|       String type = networkInfo.getTypeName(); | ||||
|       if (type.equalsIgnoreCase("WIFI")) { | ||||
|         netWorkType = NETWORK_TYPE_WIFI; | ||||
|       } else if (type.equalsIgnoreCase("MOBILE")) { | ||||
|         String proxyHost = android.net.Proxy.getDefaultHost(); | ||||
|         netWorkType = TextUtils.isEmpty(proxyHost) ? (isFastMobileNetwork(context) ? NETWORK_TYPE_3G | ||||
|             : NETWORK_TYPE_2G) : NETWORK_TYPE_WAP; | ||||
|       } | ||||
|     } else { | ||||
|       netWorkType = NETWORK_TYPE_INVALID; | ||||
|     } | ||||
|     return netWorkType; | ||||
|   } | ||||
| 
 | ||||
|   private static boolean isFastMobileNetwork(Context context) { | ||||
|     TelephonyManager telephonyManager = | ||||
|         (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); | ||||
|     switch (telephonyManager.getNetworkType()) { | ||||
|       case TelephonyManager.NETWORK_TYPE_1xRTT: | ||||
|         return false; // ~ 50-100 kbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_CDMA: | ||||
|         return false; // ~ 14-64 kbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_EDGE: | ||||
|         return false; // ~ 50-100 kbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_EVDO_0: | ||||
|         return true; // ~ 400-1000 kbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_EVDO_A: | ||||
|         return true; // ~ 600-1400 kbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_GPRS: | ||||
|         return false; // ~ 100 kbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_HSDPA: | ||||
|         return true; // ~ 2-14 Mbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_HSPA: | ||||
|         return true; // ~ 700-1700 kbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_HSUPA: | ||||
|         return true; // ~ 1-23 Mbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_UMTS: | ||||
|         return true; // ~ 400-7000 kbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_EHRPD: | ||||
|         return true; // ~ 1-2 Mbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_EVDO_B: | ||||
|         return true; // ~ 5 Mbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_HSPAP: | ||||
|         return true; // ~ 10-20 Mbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_IDEN: | ||||
|         return false; // ~25 kbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_LTE: | ||||
|         return true; // ~ 10+ Mbps
 | ||||
|       case TelephonyManager.NETWORK_TYPE_UNKNOWN: | ||||
|         return false; | ||||
|       default: | ||||
|         return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 打开网络设置界面 | ||||
|    */ | ||||
|   public static void openSetting(Context context) { | ||||
|     if (AndroidVersionUtil.hasHoneycomb()) { | ||||
|       Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS); | ||||
|       intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|       context.startActivity(intent); | ||||
|     } else { | ||||
|       Intent intent = new Intent("/"); | ||||
|       ComponentName cm = | ||||
|           new ComponentName("com.android.settings", "com.android.settings.WirelessSettings"); | ||||
|       intent.setComponent(cm); | ||||
|       intent.setAction("android.intent.action.VIEW"); | ||||
|       intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|       context.startActivity(intent); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,224 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.content.res.Resources; | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.BitmapFactory; | ||||
| import android.graphics.Color; | ||||
| import android.graphics.Rect; | ||||
| import android.graphics.drawable.NinePatchDrawable; | ||||
| import android.util.DisplayMetrics; | ||||
| 
 | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.IOException; | ||||
| import java.nio.ByteBuffer; | ||||
| import java.nio.ByteOrder; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| /** | ||||
|  * 加载。9图片 | ||||
|  * Time: 2:37 PM | ||||
|  */ | ||||
| public class NinePatchBitmapFactory { | ||||
| 
 | ||||
|   private static final int NO_COLOR = 0x00000001; | ||||
| 
 | ||||
|   private static final int TRANSPARENT_COLOR = 0x00000000; | ||||
| 
 | ||||
|   public static NinePatchDrawable createNinePatchDrawable(Resources res, Bitmap bitmap) { | ||||
|     RangeLists rangeLists = checkBitmap(bitmap); | ||||
|     Bitmap trimedBitmap = trimBitmap(bitmap); | ||||
|     return createNinePatchWithCapInsets(res, trimedBitmap, rangeLists.rangeListX, | ||||
|         rangeLists.rangeListY, null); | ||||
|   } | ||||
| 
 | ||||
|   public static NinePatchDrawable createNinePatchWithCapInsets(Resources res, Bitmap bitmap, | ||||
|       List<Range> rangeListX, List<Range> rangeListY, String srcName) { | ||||
|     ByteBuffer buffer = getByteBuffer(rangeListX, rangeListY); | ||||
|     return new NinePatchDrawable(res, bitmap, buffer.array(), new Rect(), srcName); | ||||
|   } | ||||
| 
 | ||||
|   private static ByteBuffer getByteBuffer(List<Range> rangeListX, List<Range> rangeListY) { | ||||
|     ByteBuffer buffer = ByteBuffer.allocate( | ||||
|         4 + 4 * 7 + 4 * 2 * rangeListX.size() + 4 * 2 * rangeListY.size() + 4 * 9) | ||||
|         .order(ByteOrder.nativeOrder()); | ||||
|     buffer.put((byte) 0x01); // was serialised
 | ||||
|     buffer.put((byte) (rangeListX.size() * 2)); // x div
 | ||||
|     buffer.put((byte) (rangeListY.size() * 2)); // y div
 | ||||
|     buffer.put((byte) 0x09); // color
 | ||||
| 
 | ||||
|     // skip
 | ||||
|     buffer.putInt(0); | ||||
|     buffer.putInt(0); | ||||
| 
 | ||||
|     // padding
 | ||||
|     buffer.putInt(0); | ||||
|     buffer.putInt(0); | ||||
|     buffer.putInt(0); | ||||
|     buffer.putInt(0); | ||||
| 
 | ||||
|     // skip 4 bytes
 | ||||
|     buffer.putInt(0); | ||||
| 
 | ||||
|     for (Range range : rangeListX) { | ||||
|       buffer.putInt(range.start); | ||||
|       buffer.putInt(range.end); | ||||
|     } | ||||
|     for (Range range : rangeListY) { | ||||
|       buffer.putInt(range.start); | ||||
|       buffer.putInt(range.end); | ||||
|     } | ||||
|     buffer.putInt(NO_COLOR); | ||||
|     buffer.putInt(NO_COLOR); | ||||
|     buffer.putInt(NO_COLOR); | ||||
|     buffer.putInt(NO_COLOR); | ||||
|     buffer.putInt(NO_COLOR); | ||||
|     buffer.putInt(NO_COLOR); | ||||
|     buffer.putInt(NO_COLOR); | ||||
|     buffer.putInt(NO_COLOR); | ||||
|     buffer.putInt(NO_COLOR); | ||||
| 
 | ||||
|     return buffer; | ||||
|   } | ||||
| 
 | ||||
|   public static class RangeLists { | ||||
|     public List<Range> rangeListX; | ||||
|     public List<Range> rangeListY; | ||||
|   } | ||||
| 
 | ||||
|   public static class Range { | ||||
|     public int start; | ||||
|     public int end; | ||||
|   } | ||||
| 
 | ||||
|   public static RangeLists checkBitmap(Bitmap bitmap) { | ||||
|     int width = bitmap.getWidth(); | ||||
|     int height = bitmap.getHeight(); | ||||
| 
 | ||||
|     List<Range> rangeListX = new ArrayList<Range>(); | ||||
| 
 | ||||
|     int pos = -1; | ||||
|     for (int i = 1; i < width - 1; i++) { | ||||
|       int color = bitmap.getPixel(i, 0); | ||||
|       int alpha = Color.alpha(color); | ||||
|       int red = Color.red(color); | ||||
|       int green = Color.green(color); | ||||
|       int blue = Color.blue(color); | ||||
|       //			System.out.println( String.valueOf(alpha) + "," + String.valueOf(red) + "," + String.valueOf(green) + "," + String.valueOf(blue) );
 | ||||
|       if (alpha == 255 && red == 0 && green == 0 && blue == 0) { | ||||
|         if (pos == -1) { | ||||
|           pos = i - 1; | ||||
|         } | ||||
|       } else { | ||||
|         if (pos != -1) { | ||||
|           Range range = new Range(); | ||||
|           range.start = pos; | ||||
|           range.end = i - 1; | ||||
|           rangeListX.add(range); | ||||
|           pos = -1; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     if (pos != -1) { | ||||
|       Range range = new Range(); | ||||
|       range.start = pos; | ||||
|       range.end = width - 2; | ||||
|       rangeListX.add(range); | ||||
|     } | ||||
|     for (Range range : rangeListX) { | ||||
|       System.out.println("(" + range.start + "," + range.end + ")"); | ||||
|     } | ||||
| 
 | ||||
|     List<Range> rangeListY = new ArrayList<Range>(); | ||||
| 
 | ||||
|     pos = -1; | ||||
|     for (int i = 1; i < height - 1; i++) { | ||||
|       int color = bitmap.getPixel(0, i); | ||||
|       int alpha = Color.alpha(color); | ||||
|       int red = Color.red(color); | ||||
|       int green = Color.green(color); | ||||
|       int blue = Color.blue(color); | ||||
|       if (alpha == 255 && red == 0 && green == 0 && blue == 0) { | ||||
|         if (pos == -1) { | ||||
|           pos = i - 1; | ||||
|         } | ||||
|       } else { | ||||
|         if (pos != -1) { | ||||
|           Range range = new Range(); | ||||
|           range.start = pos; | ||||
|           range.end = i - 1; | ||||
|           rangeListY.add(range); | ||||
|           pos = -1; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     if (pos != -1) { | ||||
|       Range range = new Range(); | ||||
|       range.start = pos; | ||||
|       range.end = height - 2; | ||||
|       rangeListY.add(range); | ||||
|     } | ||||
|     for (Range range : rangeListY) { | ||||
|       System.out.println("(" + range.start + "," + range.end + ")"); | ||||
|     } | ||||
| 
 | ||||
|     RangeLists rangeLists = new RangeLists(); | ||||
|     rangeLists.rangeListX = rangeListX; | ||||
|     rangeLists.rangeListY = rangeListY; | ||||
| 
 | ||||
|     return rangeLists; | ||||
|   } | ||||
| 
 | ||||
|   public static Bitmap trimBitmap(Bitmap bitmap) { | ||||
|     int width = bitmap.getWidth(); | ||||
|     int height = bitmap.getHeight(); | ||||
| 
 | ||||
|     Bitmap result = Bitmap.createBitmap(bitmap, 1, 1, width - 2, height - 2); | ||||
| 
 | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   public static Bitmap loadBitmap(File file) { | ||||
|     BufferedInputStream bis = null; | ||||
|     try { | ||||
|       bis = new BufferedInputStream(new FileInputStream(file)); | ||||
|       return BitmapFactory.decodeStream(bis); | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } finally { | ||||
|       try { | ||||
|         bis.close(); | ||||
|       } catch (Exception e) { | ||||
| 
 | ||||
|       } | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   public static String getDensityPostfix(Resources res) { | ||||
|     String result = null; | ||||
|     switch (res.getDisplayMetrics().densityDpi) { | ||||
|       case DisplayMetrics.DENSITY_LOW: | ||||
|         result = "ldpi"; | ||||
|         break; | ||||
|       case DisplayMetrics.DENSITY_MEDIUM: | ||||
|         result = "mdpi"; | ||||
|         break; | ||||
|       case DisplayMetrics.DENSITY_HIGH: | ||||
|         result = "hdpi"; | ||||
|         break; | ||||
|       case DisplayMetrics.DENSITY_XHIGH: | ||||
|         result = "xhdpi"; | ||||
|         break; | ||||
|       case DisplayMetrics.DENSITY_XXHIGH: | ||||
|         result = "xxhdpi"; | ||||
|         break; | ||||
|       case DisplayMetrics.DENSITY_XXXHIGH: | ||||
|         result = "xxxhdpi"; | ||||
|         break; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,49 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2016/7/6. | ||||
|  */ | ||||
| public class ObjUtil { | ||||
| 
 | ||||
|   /** | ||||
|    * 打印Map | ||||
|    */ | ||||
|   public static String getMapString(Map map) { | ||||
|     Set set = map.keySet(); | ||||
|     if (set.size() < 1) { | ||||
|       return "[]"; | ||||
|     } | ||||
|     StringBuilder strBuilder = new StringBuilder(); | ||||
|     Object[] array = set.toArray(); | ||||
|     strBuilder.append("[").append(array[0]).append("=").append(map.get(array[0])); | ||||
|     for (int i = 1; i < array.length; ++i) { | ||||
|       strBuilder.append(", "); | ||||
|       strBuilder.append(array[i]).append("="); | ||||
|       strBuilder.append(map.get(array[i])); | ||||
|     } | ||||
|     strBuilder.append("]"); | ||||
|     return strBuilder.toString(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 通过Value 获取key | ||||
|    */ | ||||
|   public static <T, E> T getKeyByValue(Map<T, E> map, E value) { | ||||
|     for (Map.Entry<T, E> entry : map.entrySet()) { | ||||
|       if (equals(value, entry.getValue())) { | ||||
|         return entry.getKey(); | ||||
|       } | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 比较两个对象是否相等 | ||||
|    */ | ||||
|   public static boolean equals(Object a, Object b) { | ||||
|     return (a == null) ? (b == null) : a.equals(b); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,150 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.res.AssetManager; | ||||
| import android.content.res.XmlResourceParser; | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| import com.arialyy.frame.util.show.FL; | ||||
| import com.arialyy.frame.util.show.L; | ||||
| 
 | ||||
| import org.xmlpull.v1.XmlPullParser; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | ||||
| 
 | ||||
| import dalvik.system.PathClassLoader; | ||||
| 
 | ||||
| /** | ||||
|  * Created by lyy on 2015/7/30. | ||||
|  * 反射工具类 | ||||
|  */ | ||||
| public class ReflectionUtil { | ||||
|   private static final String TAG = "ReflectionUtil"; | ||||
|   private static final String ID = "$id"; | ||||
|   private static final String LAYOUT = "$layout"; | ||||
|   private static final String STYLE = "$style"; | ||||
|   private static final String STRING = "$string"; | ||||
|   private static final String DRAWABLE = "$drawable"; | ||||
|   private static final String ARRAY = "$array"; | ||||
|   private static final String COLOR = "color"; | ||||
|   private static final String ANIM = "anim"; | ||||
| 
 | ||||
|   /** | ||||
|    * 从SDcard读取layout | ||||
|    */ | ||||
|   public static XmlPullParser getLayoutXmlPullParser(Context context, String filePath, | ||||
|       String fileName) { | ||||
|     XmlResourceParser paser = null; | ||||
|     AssetManager asset = context.getResources().getAssets(); | ||||
|     try { | ||||
|       Method method = asset.getClass().getMethod("addAssetPath", String.class); | ||||
|       int cookie = (Integer) method.invoke(asset, filePath); | ||||
|       if (cookie == 0) { | ||||
|         FL.e(TAG, "加载路径失败"); | ||||
|       } | ||||
|       paser = asset.openXmlResourceParser(cookie, fileName + ".xml"); | ||||
|     } catch (NoSuchMethodException e) { | ||||
|       e.printStackTrace(); | ||||
|     } catch (InvocationTargetException e) { | ||||
|       e.printStackTrace(); | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } catch (IllegalAccessException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return paser; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取类里面的所在字段 | ||||
|    */ | ||||
|   public static Field[] getFields(Class clazz) { | ||||
|     Field[] fields = null; | ||||
|     fields = clazz.getDeclaredFields(); | ||||
|     if (fields == null || fields.length == 0) { | ||||
|       Class superClazz = clazz.getSuperclass(); | ||||
|       if (superClazz != null) { | ||||
|         fields = getFields(superClazz); | ||||
|       } | ||||
|     } | ||||
|     return fields; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取类里面的指定对象,如果该类没有则从父类查询 | ||||
|    */ | ||||
|   public static Field getField(Class clazz, String name) { | ||||
|     Field field = null; | ||||
|     try { | ||||
|       field = clazz.getDeclaredField(name); | ||||
|     } catch (NoSuchFieldException e) { | ||||
|       try { | ||||
|         field = clazz.getField(name); | ||||
|       } catch (NoSuchFieldException e1) { | ||||
|         if (clazz.getSuperclass() == null) { | ||||
|           return field; | ||||
|         } else { | ||||
|           field = getField(clazz.getSuperclass(), name); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     if (field != null) { | ||||
|       field.setAccessible(true); | ||||
|     } | ||||
|     return field; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 利用递归找一个类的指定方法,如果找不到,去父亲里面找直到最上层Object对象为止。 | ||||
|    * | ||||
|    * @param clazz 目标类 | ||||
|    * @param methodName 方法名 | ||||
|    * @param params 方法参数类型数组 | ||||
|    * @return 方法对象 | ||||
|    */ | ||||
|   public static Method getMethod(Class clazz, String methodName, final Class<?>... params) { | ||||
|     Method method = null; | ||||
|     try { | ||||
|       method = clazz.getDeclaredMethod(methodName, params); | ||||
|     } catch (NoSuchMethodException e) { | ||||
|       try { | ||||
|         method = clazz.getMethod(methodName, params); | ||||
|       } catch (NoSuchMethodException ex) { | ||||
|         if (clazz.getSuperclass() == null) { | ||||
|           L.e(TAG, "无法找到" + methodName + "方法"); | ||||
|           FL.e(TAG, FL.getExceptionString(e)); | ||||
|           return method; | ||||
|         } else { | ||||
|           method = getMethod(clazz.getSuperclass(), methodName, params); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     if (method != null) { | ||||
|       method.setAccessible(true); | ||||
|     } | ||||
|     return method; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 加载指定的反射类 | ||||
|    */ | ||||
|   public static Class<?> loadClass(Context context, String ClassName) { | ||||
|     String packageName = AndroidUtils.getPackageName(context); | ||||
|     String sourcePath = AndroidUtils.getSourcePath(context, packageName); | ||||
|     if (!TextUtils.isEmpty(sourcePath)) { | ||||
|       PathClassLoader cl = | ||||
|           new PathClassLoader(sourcePath, "/data/app/", ClassLoader.getSystemClassLoader()); | ||||
|       try { | ||||
|         return cl.loadClass(ClassName); | ||||
|       } catch (ClassNotFoundException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|     } else { | ||||
|       FL.e(TAG, "没有【" + sourcePath + "】目录"); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,95 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| /** | ||||
|  * Created by AriaLyy on 2015/1/10. | ||||
|  * 正则表达式规则 | ||||
|  */ | ||||
| public class RegularExpression { | ||||
| 
 | ||||
|   /** | ||||
|    * APK包 | ||||
|    */ | ||||
|   public static String APK = "^(.*)\\.(apk)$"; | ||||
|   /** | ||||
|    * 视频 | ||||
|    */ | ||||
|   public static String VIDEO = "^(.*)\\.(mpeg-4|h.264|h.265|rmvb|xvid|vp6|h.263|mpeg-1|mpeg-2|avi|" | ||||
|       + "mov|mkv|flv|3gp|3g2|asf|wmv|mp4|m4v|tp|ts|mtp|m2t)$"; | ||||
|   /** | ||||
|    * 音频 | ||||
|    */ | ||||
|   public static String MUSIC = "^(.*)\\.(aac|vorbis|flac|mp3|mp2|wma)$"; | ||||
| 
 | ||||
|   /** | ||||
|    * 文本 | ||||
|    */ | ||||
|   public static String TEXT = "^(.*)\\.(txt|xml|html)$"; | ||||
|   /** | ||||
|    * 压缩包 | ||||
|    */ | ||||
|   public static String ZIP = "^(.*)\\.(zip|rar|7z)$"; | ||||
|   /** | ||||
|    * DOC | ||||
|    */ | ||||
|   public static String DOC = "^(.*)\\.(doc|docx)"; | ||||
|   /** | ||||
|    * PPT | ||||
|    */ | ||||
|   public static String PPT = "^(.*)\\.(ppt|pptx)"; | ||||
|   /** | ||||
|    * xls | ||||
|    */ | ||||
|   public static String XLS = "^(.*)\\.(xls|xlsx)"; | ||||
|   /** | ||||
|    * vcf | ||||
|    */ | ||||
|   public static String VCF = "^(.*)\\.(vcf)"; | ||||
|   /** | ||||
|    * pdf | ||||
|    */ | ||||
|   public static String PDF = "^(.*)\\.(pdf)"; | ||||
|   /** | ||||
|    * SQL | ||||
|    */ | ||||
|   public static String SQL = "^(.*)\\.(sql|db)"; | ||||
| 
 | ||||
|   /** | ||||
|    * 图片 | ||||
|    */ | ||||
|   public static String IMG = "^(.*)\\.(jpg|bmp|png|gif|jpeg|psd)"; | ||||
| 
 | ||||
|   /** | ||||
|    * 中文 | ||||
|    */ | ||||
|   public static String CHINESE = "[\\u4e00-\\u9fa5]"; | ||||
| 
 | ||||
|   /** | ||||
|    * 首尾空白字符 | ||||
|    */ | ||||
|   public static String START_OR_END_NONE = "^\\s*|\\s*"; | ||||
| 
 | ||||
|   /** | ||||
|    * 空白行 | ||||
|    */ | ||||
|   public static String NOTE_ITEM = "\\n\\s*\\r"; | ||||
| 
 | ||||
|   /** | ||||
|    * 邮箱 | ||||
|    */ | ||||
|   public static String EMAIL = "\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"; | ||||
| 
 | ||||
|   /** | ||||
|    * url | ||||
|    */ | ||||
|   public static String URL = "[a-zA-z]+://[^\\s]*"; | ||||
| 
 | ||||
|   /** | ||||
|    * QQ | ||||
|    */ | ||||
|   public static String QQ = "[1-9][0-9]{4,}"; | ||||
| 
 | ||||
|   /** | ||||
|    * IP | ||||
|    */ | ||||
|   public static String IP = "\\d+\\.\\d+\\.\\d+\\.\\d+"; | ||||
| } | ||||
| @ -0,0 +1,208 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.annotation.TargetApi; | ||||
| import android.app.Activity; | ||||
| import android.content.ContentResolver; | ||||
| import android.content.Context; | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.ColorMatrix; | ||||
| import android.graphics.ColorMatrixColorFilter; | ||||
| import android.graphics.Paint; | ||||
| import android.graphics.Rect; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.provider.Settings; | ||||
| import android.util.DisplayMetrics; | ||||
| import android.view.View; | ||||
| import android.view.WindowManager; | ||||
| 
 | ||||
| /** | ||||
|  * Created by AriaLyy on 2015/1/22. | ||||
|  * 屏幕工具 | ||||
|  */ | ||||
| public class ScreenUtil { | ||||
| 
 | ||||
|   private volatile static ScreenUtil mUtil = null; | ||||
|   private static final Object LOCK = new Object(); | ||||
| 
 | ||||
|   private ScreenUtil() { | ||||
|   } | ||||
| 
 | ||||
|   public static ScreenUtil getInstance() { | ||||
|     if (mUtil == null) { | ||||
|       synchronized (LOCK) { | ||||
|         if (mUtil == null) { | ||||
|           mUtil = new ScreenUtil(); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return mUtil; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置灰度 | ||||
|    * | ||||
|    * @param greyScale true:灰度 | ||||
|    */ | ||||
|   @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void setGreyScale(View v, boolean greyScale) { | ||||
|     if (greyScale) { | ||||
|       // Create a paint object with 0 saturation (black and white)
 | ||||
|       ColorMatrix cm = new ColorMatrix(); | ||||
|       cm.setSaturation(0); | ||||
|       Paint greyScalePaint = new Paint(); | ||||
|       greyScalePaint.setColorFilter(new ColorMatrixColorFilter(cm)); | ||||
|       // Create a hardware layer with the greyScale paint
 | ||||
|       v.setLayerType(View.LAYER_TYPE_HARDWARE, greyScalePaint); | ||||
|     } else { | ||||
|       // Remove the hardware layer
 | ||||
|       v.setLayerType(View.LAYER_TYPE_NONE, null); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获得屏幕高度 | ||||
|    */ | ||||
|   public int getScreenWidth(Context context) { | ||||
|     WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); | ||||
|     DisplayMetrics outMetrics = new DisplayMetrics(); | ||||
|     wm.getDefaultDisplay().getMetrics(outMetrics); | ||||
|     return outMetrics.widthPixels; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获得屏幕宽度 | ||||
|    */ | ||||
|   public int getScreenHeight(Context context) { | ||||
|     WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); | ||||
|     DisplayMetrics outMetrics = new DisplayMetrics(); | ||||
|     wm.getDefaultDisplay().getMetrics(outMetrics); | ||||
|     return outMetrics.heightPixels; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获得状态栏的高度 | ||||
|    */ | ||||
|   public int getStatusHeight(Context context) { | ||||
| 
 | ||||
|     int statusHeight = -1; | ||||
|     try { | ||||
|       Class<?> clazz = Class.forName("com.android.internal.R$dimen"); | ||||
|       Object object = clazz.newInstance(); | ||||
|       int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString()); | ||||
|       statusHeight = context.getResources().getDimensionPixelSize(height); | ||||
|     } catch (Exception e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return statusHeight; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取当前屏幕截图,包含状态栏 | ||||
|    * | ||||
|    * @return error return null | ||||
|    */ | ||||
|   public Bitmap snapShotWithStatusBar(Activity activity) { | ||||
|     final View view = activity.getWindow().getDecorView(); | ||||
|     view.setDrawingCacheEnabled(true); | ||||
|     view.buildDrawingCache(); | ||||
|     int width = getScreenWidth(activity); | ||||
|     int height = getScreenHeight(activity); | ||||
|     //        view.layout(0, 0, width, height);
 | ||||
| 
 | ||||
|     Bitmap bmp = view.getDrawingCache(); | ||||
|     if (bmp == null) { | ||||
|       return null; | ||||
|     } | ||||
|     Bitmap bp = null; | ||||
|     bp = Bitmap.createBitmap(bmp, 0, 0, width, height); | ||||
|     view.destroyDrawingCache(); | ||||
|     return bp; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取当前屏幕截图,不包含状态栏 | ||||
|    */ | ||||
|   public Bitmap snapShotWithoutStatusBar(Activity activity) { | ||||
|     View view = activity.getWindow().getDecorView(); | ||||
|     view.setDrawingCacheEnabled(true); | ||||
|     view.buildDrawingCache(); | ||||
|     Bitmap bmp = view.getDrawingCache(); | ||||
|     Rect frame = new Rect(); | ||||
|     activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); | ||||
|     int statusBarHeight = frame.top; | ||||
| 
 | ||||
|     int width = getScreenWidth(activity); | ||||
|     int height = getScreenHeight(activity); | ||||
|     Bitmap bp = null; | ||||
|     bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height - statusBarHeight); | ||||
|     view.destroyDrawingCache(); | ||||
|     return bp; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 判断是否开启了自动亮度调节 | ||||
|    */ | ||||
|   public boolean isAutoBrightness(ContentResolver aContentResolver) { | ||||
|     boolean automicBrightness = false; | ||||
|     try { | ||||
|       automicBrightness = | ||||
|           Settings.System.getInt(aContentResolver, Settings.System.SCREEN_BRIGHTNESS_MODE) | ||||
|               == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; | ||||
|     } catch (Settings.SettingNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return automicBrightness; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取屏幕的亮度 | ||||
|    */ | ||||
|   public float getScreenBrightness(Activity activity) { | ||||
|     int nowBrightnessValue = 0; | ||||
|     ContentResolver resolver = activity.getContentResolver(); | ||||
|     try { | ||||
|       nowBrightnessValue = Settings.System.getInt(resolver, Settings.System.SCREEN_BRIGHTNESS); | ||||
|     } catch (Exception e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return nowBrightnessValue; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 设置亮度(手动设置亮度,需要关闭自动设置亮度的开关) | ||||
|    * | ||||
|    * @param brightness 0-1 | ||||
|    */ | ||||
|   public void setBrightness(Activity activity, float brightness) { | ||||
|     stopAutoBrightness(activity); | ||||
|     WindowManager.LayoutParams lp = activity.getWindow().getAttributes(); | ||||
|     lp.screenBrightness = brightness * (1f / 255f); | ||||
|     activity.getWindow().setAttributes(lp); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 停止自动亮度调节 | ||||
|    */ | ||||
|   public void stopAutoBrightness(Activity activity) { | ||||
|     Settings.System.putInt(activity.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, | ||||
|         Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 开启亮度自动调节 | ||||
|    */ | ||||
|   public void startAutoBrightness(Activity activity) { | ||||
|     Settings.System.putInt(activity.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, | ||||
|         Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 保存亮度设置状态 | ||||
|    */ | ||||
|   public void saveBrightness(ContentResolver resolver, int brightness) { | ||||
|     Uri uri = Settings.System.getUriFor("screen_brightness"); | ||||
|     Settings.System.putInt(resolver, "screen_brightness", brightness); | ||||
|     // resolver.registerContentObserver(uri, true, myContentObserver);
 | ||||
|     resolver.notifyChange(uri, null); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,145 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.SharedPreferences; | ||||
| import android.content.SharedPreferences.Editor; | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| import com.google.gson.Gson; | ||||
| 
 | ||||
| /** | ||||
|  * 配置文件工具类 | ||||
|  * | ||||
|  * @author Administrator | ||||
|  */ | ||||
| public class SharePreUtil { | ||||
| 
 | ||||
|   /** | ||||
|    * 删除键值对 | ||||
|    */ | ||||
|   public static void removeKey(String preName, Context context, String key) { | ||||
|     SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE); | ||||
|     Editor editor = pre.edit(); | ||||
|     editor.remove(key); | ||||
|     editor.commit(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从配置文件读取字符串 | ||||
|    * | ||||
|    * @param preName 配置文件名 | ||||
|    * @param key 字符串键值 | ||||
|    * @return 键值对应的字符串, 默认返回"" | ||||
|    */ | ||||
|   public static String getString(String preName, Context context, String key) { | ||||
|     SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE); | ||||
|     return pre.getString(key, ""); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从配置文件读取int数据 | ||||
|    * | ||||
|    * @param preName 配置文件名 | ||||
|    * @param key int的键值 | ||||
|    * @return 键值对应的int, 默认返回-1 | ||||
|    */ | ||||
|   public static int getInt(String preName, Context context, String key) { | ||||
|     SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE); | ||||
|     return pre.getInt(key, -1); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从配置文件读取Boolean值 | ||||
|    * | ||||
|    * @return 如果没有,默认返回false | ||||
|    */ | ||||
|   public static Boolean getBoolean(String preName, Context context, String key) { | ||||
|     SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE); | ||||
|     return pre.getBoolean(key, false); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从配置文件获取float数据 | ||||
|    * | ||||
|    * @return 默认返回0.0f | ||||
|    */ | ||||
|   public static float getFloat(String preName, Context context, String key) { | ||||
|     SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE); | ||||
|     return pre.getFloat(key, 0.0f); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从配置文件获取对象 | ||||
|    */ | ||||
|   public static <T> T getObject(String preName, Context context, String key, Class<T> clazz) { | ||||
|     SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE); | ||||
|     String str = pre.getString(key, ""); | ||||
|     return TextUtils.isEmpty(str) ? null : new Gson().fromJson(str, clazz); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 存储字符串到配置文件 | ||||
|    * | ||||
|    * @param preName 配置文件名 | ||||
|    * @param key 存储的键值 | ||||
|    * @param value 需要存储的字符串 | ||||
|    * @return 成功标志 | ||||
|    */ | ||||
|   public static Boolean putString(String preName, Context context, String key, String value) { | ||||
|     SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE); | ||||
|     Editor editor = pre.edit(); | ||||
|     editor.putString(key, value); | ||||
|     return editor.commit(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 保存Float数据到配置文件 | ||||
|    */ | ||||
|   public static Boolean putFloat(String preName, Context context, String key, float value) { | ||||
|     SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE); | ||||
|     Editor editor = pre.edit(); | ||||
|     editor.putFloat(key, value); | ||||
|     return editor.commit(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 存储数字到配置文件 | ||||
|    * | ||||
|    * @param preName 配置文件名 | ||||
|    * @param key 存储的键值 | ||||
|    * @param value 需要存储的数字 | ||||
|    * @return 成功标志 | ||||
|    */ | ||||
|   public static Boolean putInt(String preName, Context context, String key, int value) { | ||||
|     SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE); | ||||
|     Editor editor = pre.edit(); | ||||
|     editor.putInt(key, value); | ||||
|     return editor.commit(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 存储Boolean值到配置文件 | ||||
|    * | ||||
|    * @param preName 配置文件名 | ||||
|    * @param key 键值 | ||||
|    * @param value 需要存储的boolean值 | ||||
|    */ | ||||
|   public static Boolean putBoolean(String preName, Context context, String key, Boolean value) { | ||||
|     SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE); | ||||
|     Editor editor = pre.edit(); | ||||
|     editor.putBoolean(key, value); | ||||
|     return editor.commit(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 存放对象 | ||||
|    */ | ||||
|   public static Boolean putObject(String preName, Context context, String key, Class<?> clazz, | ||||
|       Object obj) { | ||||
|     String str = new Gson().toJson(obj, clazz); | ||||
|     SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE); | ||||
|     Editor editor = pre.edit(); | ||||
|     editor.putString(key, str); | ||||
|     return editor.commit(); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,212 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import java.io.BufferedReader; | ||||
| import java.io.DataOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStreamReader; | ||||
| import java.util.List; | ||||
| 
 | ||||
| /** | ||||
|  * ShellUtils | ||||
|  * <ul> | ||||
|  * <li>{@link ShellUtils#checkRootPermission()}</li> | ||||
|  * </ul> | ||||
|  * <ul> | ||||
|  * <li>{@link ShellUtils#execCommand(String, boolean)}</li> | ||||
|  * <li>{@link ShellUtils#execCommand(String, boolean, boolean)}</li> | ||||
|  * <li>{@link ShellUtils#execCommand(List, boolean)}</li> | ||||
|  * <li>{@link ShellUtils#execCommand(List, boolean, boolean)}</li> | ||||
|  * <li>{@link ShellUtils#execCommand(String[], boolean)}</li> | ||||
|  * <li>{@link ShellUtils#execCommand(String[], boolean, boolean)}</li> | ||||
|  * </ul> | ||||
|  * | ||||
|  * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16 | ||||
|  */ | ||||
| public class ShellUtils { | ||||
|   public static final String COMMAND_SU = "su"; | ||||
|   public static final String COMMAND_SH = "sh"; | ||||
|   public static final String COMMAND_EXIT = "exit\n"; | ||||
|   public static final String COMMAND_LINE_END = "\n"; | ||||
| 
 | ||||
|   /** | ||||
|    * check whether has root permission | ||||
|    */ | ||||
|   public static boolean checkRootPermission() { | ||||
|     return execCommand("echo root", true, false).result == 0; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * execute shell command, default return result msg | ||||
|    * | ||||
|    * @param command command | ||||
|    * @param isRoot whether need to run with root | ||||
|    * @see ShellUtils#execCommand(String[], boolean, boolean) | ||||
|    */ | ||||
|   public static CommandResult execCommand(String command, boolean isRoot) { | ||||
|     return execCommand(new String[] { command }, isRoot, true); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * execute shell commands, default return result msg | ||||
|    * | ||||
|    * @param commands command list | ||||
|    * @param isRoot whether need to run with root | ||||
|    * @see ShellUtils#execCommand(String[], boolean, boolean) | ||||
|    */ | ||||
|   public static CommandResult execCommand(List<String> commands, boolean isRoot) { | ||||
|     return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, true); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * execute shell commands, default return result msg | ||||
|    * | ||||
|    * @param commands command array | ||||
|    * @param isRoot whether need to run with root | ||||
|    * @see ShellUtils#execCommand(String[], boolean, boolean) | ||||
|    */ | ||||
|   public static CommandResult execCommand(String[] commands, boolean isRoot) { | ||||
|     return execCommand(commands, isRoot, true); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * execute shell command | ||||
|    * | ||||
|    * @param command command | ||||
|    * @param isRoot whether need to run with root | ||||
|    * @param isNeedResultMsg whether need result msg | ||||
|    * @see ShellUtils#execCommand(String[], boolean, boolean) | ||||
|    */ | ||||
|   public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) { | ||||
|     return execCommand(new String[] { command }, isRoot, isNeedResultMsg); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * execute shell commands | ||||
|    * | ||||
|    * @param commands command list | ||||
|    * @param isRoot whether need to run with root | ||||
|    * @param isNeedResultMsg whether need result msg | ||||
|    * @see ShellUtils#execCommand(String[], boolean, boolean) | ||||
|    */ | ||||
|   public static CommandResult execCommand(List<String> commands, boolean isRoot, | ||||
|       boolean isNeedResultMsg) { | ||||
|     return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, | ||||
|         isNeedResultMsg); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * execute shell commands | ||||
|    * | ||||
|    * @param commands command array | ||||
|    * @param isRoot whether need to run with root | ||||
|    * @param isNeedResultMsg whether need result msg | ||||
|    * @return <ul> | ||||
|    * <li>if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and | ||||
|    * {@link CommandResult#errorMsg} is null.</li> | ||||
|    * <li>if {@link CommandResult#result} is -1, there maybe some excepiton.</li> | ||||
|    * </ul> | ||||
|    */ | ||||
|   public static CommandResult execCommand(String[] commands, boolean isRoot, | ||||
|       boolean isNeedResultMsg) { | ||||
|     int result = -1; | ||||
|     if (commands == null || commands.length == 0) { | ||||
|       return new CommandResult(result, null, null); | ||||
|     } | ||||
|     Process process = null; | ||||
|     BufferedReader successResult = null; | ||||
|     BufferedReader errorResult = null; | ||||
|     StringBuilder successMsg = null; | ||||
|     StringBuilder errorMsg = null; | ||||
|     DataOutputStream os = null; | ||||
|     try { | ||||
|       process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH); | ||||
|       os = new DataOutputStream(process.getOutputStream()); | ||||
|       for (String command : commands) { | ||||
|         if (command == null) { | ||||
|           continue; | ||||
|         } | ||||
|         // donnot use os.writeBytes(commmand), avoid chinese charset error
 | ||||
|         os.write(command.getBytes()); | ||||
|         os.writeBytes(COMMAND_LINE_END); | ||||
|         os.flush(); | ||||
|       } | ||||
|       os.writeBytes(COMMAND_EXIT); | ||||
|       os.flush(); | ||||
|       result = process.waitFor(); | ||||
|       // get command result
 | ||||
|       if (isNeedResultMsg) { | ||||
|         successMsg = new StringBuilder(); | ||||
|         errorMsg = new StringBuilder(); | ||||
|         successResult = new BufferedReader(new InputStreamReader(process.getInputStream())); | ||||
|         errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream())); | ||||
|         String s; | ||||
|         while ((s = successResult.readLine()) != null) { | ||||
|           successMsg.append(s); | ||||
|         } | ||||
|         while ((s = errorResult.readLine()) != null) { | ||||
|           errorMsg.append(s); | ||||
|         } | ||||
|       } | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } catch (Exception e) { | ||||
|       e.printStackTrace(); | ||||
|     } finally { | ||||
|       try { | ||||
|         if (os != null) { | ||||
|           os.close(); | ||||
|         } | ||||
|         if (successResult != null) { | ||||
|           successResult.close(); | ||||
|         } | ||||
|         if (errorResult != null) { | ||||
|           errorResult.close(); | ||||
|         } | ||||
|       } catch (IOException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|       if (process != null) { | ||||
|         process.destroy(); | ||||
|       } | ||||
|     } | ||||
|     return new CommandResult(result, successMsg == null ? null : successMsg.toString(), | ||||
|         errorMsg == null ? null : errorMsg.toString()); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * result of command | ||||
|    * <ul> | ||||
|    * <li>{@link CommandResult#result} means result of command, 0 means normal, else means error, | ||||
|    * same to excute in | ||||
|    * linux shell</li> | ||||
|    * <li>{@link CommandResult#successMsg} means success message of command result</li> | ||||
|    * <li>{@link CommandResult#errorMsg} means error message of command result</li> | ||||
|    * </ul> | ||||
|    * | ||||
|    * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16 | ||||
|    */ | ||||
|   public static class CommandResult { | ||||
|     /** | ||||
|      * result of command | ||||
|      **/ | ||||
|     public int result; | ||||
|     /** | ||||
|      * success message of command result | ||||
|      **/ | ||||
|     public String successMsg; | ||||
|     /** | ||||
|      * error message of command result | ||||
|      **/ | ||||
|     public String errorMsg; | ||||
| 
 | ||||
|     public CommandResult(int result) { | ||||
|       this.result = result; | ||||
|     } | ||||
| 
 | ||||
|     public CommandResult(int result, String successMsg, String errorMsg) { | ||||
|       this.result = result; | ||||
|       this.successMsg = successMsg; | ||||
|       this.errorMsg = errorMsg; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,23 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.InputStream; | ||||
| 
 | ||||
| /** | ||||
|  * Created by AriaLyy on 2015/4/10. | ||||
|  */ | ||||
| public class StreamUtil { | ||||
|   /** | ||||
|    * 得到图片字节流 数组大小 | ||||
|    */ | ||||
|   public static byte[] readStream(InputStream inStream) throws Exception { | ||||
|     ByteArrayOutputStream outStream = new ByteArrayOutputStream(); | ||||
|     byte[] buffer = new byte[1024]; | ||||
|     int len = 0; | ||||
|     while ((len = inStream.read(buffer)) != -1) { | ||||
|       outStream.write(buffer, 0, len); | ||||
|     } | ||||
|     outStream.close(); | ||||
|     return outStream.toByteArray(); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,328 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.app.Activity; | ||||
| import android.app.Service; | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.text.Layout; | ||||
| import android.text.Spannable; | ||||
| import android.text.SpannableString; | ||||
| import android.text.SpannableStringBuilder; | ||||
| import android.text.Spanned; | ||||
| import android.text.TextPaint; | ||||
| import android.text.style.ForegroundColorSpan; | ||||
| import android.text.style.URLSpan; | ||||
| import android.text.style.UnderlineSpan; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import java.math.BigDecimal; | ||||
| import java.security.MessageDigest; | ||||
| import java.security.NoSuchAlgorithmException; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| /** | ||||
|  * 字符串工具类 | ||||
|  * | ||||
|  * @author lyy | ||||
|  */ | ||||
| public class StringUtil { | ||||
|   public static final int APPLICATION = 0; | ||||
|   public static final int BROADCAST = 1; | ||||
|   public static final int SERVICE = 2; | ||||
|   public static final int ACTIVITY = 3; | ||||
| 
 | ||||
|   /** | ||||
|    * 获取字体长度 | ||||
|    */ | ||||
|   public static int getTextLen(TextView textView) { | ||||
|     TextPaint paint = textView.getPaint(); | ||||
|     return (int) Layout.getDesiredWidth(textView.getText().toString(), 0, | ||||
|         textView.getText().length(), paint); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 给某段支付设置下划线 | ||||
|    */ | ||||
|   public static SpannableString underLineHight(String str, String underLineStr) { | ||||
|     if (!str.contains(underLineStr)) { | ||||
|       return null; | ||||
|     } | ||||
|     // 创建一个 SpannableString对象
 | ||||
|     SpannableString sp = new SpannableString(str); | ||||
|     int index = str.indexOf(underLineStr); | ||||
|     //设置背景颜色, StrikethroughSpan()是设置中划线
 | ||||
|     sp.setSpan(new UnderlineSpan(), index, index + underLineStr.length(), | ||||
|         Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); | ||||
|     return sp; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 高亮所有关键字 | ||||
|    * | ||||
|    * @param str 这个字符串 | ||||
|    * @param key 关键字 | ||||
|    */ | ||||
|   public static SpannableString highlightKeyword(String str, String key, int highlightColor) { | ||||
|     if (!str.contains(key)) { | ||||
|       return null; | ||||
|     } | ||||
|     SpannableString sp = new SpannableString(str); | ||||
|     key = Pattern.quote(key); | ||||
|     Pattern p = Pattern.compile(key); | ||||
|     Matcher m = p.matcher(str); | ||||
| 
 | ||||
|     while (m.find()) {  //通过正则查找,逐个高亮
 | ||||
|       int start = m.start(); | ||||
|       int end = m.end(); | ||||
|       sp.setSpan(new ForegroundColorSpan(highlightColor), start, end, | ||||
|           Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); | ||||
|     } | ||||
|     return sp; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 创建一个含有超链接的字符串 | ||||
|    * | ||||
|    * @param text 整段字符串 | ||||
|    * @param clickText 含有超链接的字符 | ||||
|    * @param url 超链接 | ||||
|    */ | ||||
|   public static SpannableString createLinkText(String text, String clickText, String url) { | ||||
|     if (!text.contains(clickText)) { | ||||
|       return null; | ||||
|     } | ||||
|     SpannableString sp = new SpannableString(text); | ||||
|     int index = text.indexOf(clickText); | ||||
|     // 设置超链接
 | ||||
|     sp.setSpan(new URLSpan(url), index, index + clickText.length(), | ||||
|         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); | ||||
|     return sp; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 将缓存的key转换为hash码 | ||||
|    * | ||||
|    * @param key 缓存的key | ||||
|    * @return 转换后的key的值, 系统便是通过该key来读写缓存 | ||||
|    */ | ||||
|   public static String keyToHashKey(String key) { | ||||
|     String cacheKey; | ||||
|     try { | ||||
|       final MessageDigest mDigest = MessageDigest.getInstance("MD5"); | ||||
|       mDigest.update(key.getBytes()); | ||||
|       cacheKey = bytesToHexString(mDigest.digest()); | ||||
|     } catch (NoSuchAlgorithmException e) { | ||||
|       cacheKey = String.valueOf(key.hashCode()); | ||||
|     } | ||||
|     return cacheKey; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 读取Activity节点的meta-data | ||||
|    */ | ||||
|   public static String getActivityMetaData(Activity activity, String key) { | ||||
|     try { | ||||
|       return activity.getPackageManager() | ||||
|           .getActivityInfo(activity.getComponentName(), | ||||
|               PackageManager.GET_META_DATA).metaData.getString(key); | ||||
|     } catch (PackageManager.NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 读取Service节点的meta-data | ||||
|    * | ||||
|    * @param serviceClazz 服务的class | ||||
|    */ | ||||
|   public static String getServiceMetaData(Context context, Class<? extends Service> serviceClazz, | ||||
|       String key) { | ||||
|     try { | ||||
|       return context.getPackageManager() | ||||
|           .getServiceInfo(new ComponentName(context, serviceClazz), | ||||
|               PackageManager.GET_META_DATA).metaData.getString(key); | ||||
|     } catch (PackageManager.NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 读取BroadCast节点meta-data数据 | ||||
|    * | ||||
|    * @param receiverClazz 广播接收器的class | ||||
|    */ | ||||
|   public static String getBroadCasetMetaData(Context context, | ||||
|       Class<? extends BroadcastReceiver> receiverClazz, String key) { | ||||
|     try { | ||||
|       return context.getPackageManager() | ||||
|           .getReceiverInfo(new ComponentName(context, receiverClazz), | ||||
|               PackageManager.GET_META_DATA).metaData.getString(key); | ||||
|     } catch (PackageManager.NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 读取Application节点的meta-data数据 | ||||
|    */ | ||||
|   public static String getApplicationMetaData(Context context, String key) { | ||||
|     try { | ||||
|       return context.getPackageManager() | ||||
|           .getApplicationInfo(context.getPackageName(), | ||||
|               PackageManager.GET_META_DATA).metaData.getString(key); | ||||
|     } catch (PackageManager.NameNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 用AES算法解密加密的密码 | ||||
|    * | ||||
|    * @param seed 密钥 | ||||
|    * @param password 加密的密码 | ||||
|    * @return 解密后的密码, 默认返回"" | ||||
|    */ | ||||
|   public static String decryptPassword(String seed, String password) { | ||||
|     try { | ||||
|       return AESEncryption.decryptString(seed, password); | ||||
|     } catch (Exception e) { | ||||
|       e.printStackTrace(); | ||||
|     } | ||||
|     return ""; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从XML读取字符串 | ||||
|    * | ||||
|    * @param id 字符串id | ||||
|    */ | ||||
|   public static String getStringFromXML(Context context, int id) { | ||||
|     return context.getResources().getString(id); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从xml读取字符串数组 | ||||
|    */ | ||||
|   public static String[] getStringArrayFromXML(Context context, int id) { | ||||
|     return context.getResources().getStringArray(id); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 将字符串数组转换为list | ||||
|    */ | ||||
|   public static List<String> stringArray2List(String[] strArray) { | ||||
|     List<String> list = new ArrayList<String>(); | ||||
|     Collections.addAll(list, strArray); | ||||
|     return list; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 高亮整段字符串 | ||||
|    */ | ||||
|   public static SpannableStringBuilder highLightStr(String str, int color) { | ||||
|     SpannableStringBuilder style = new SpannableStringBuilder(str); | ||||
|     style.setSpan(new ForegroundColorSpan(color), 0, str.length(), | ||||
|         Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); | ||||
|     return style; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 高亮代码片段 | ||||
|    * | ||||
|    * @param str 整段字符串 | ||||
|    * @param highLightStr 要高亮的代码段 | ||||
|    * @param color 高亮颜色 | ||||
|    */ | ||||
|   public static SpannableStringBuilder highLightStr(String str, String highLightStr, int color) { | ||||
|     int start = str.indexOf(highLightStr); | ||||
|     if (start == -1) { | ||||
|       return null; | ||||
|     } | ||||
|     SpannableStringBuilder style = new SpannableStringBuilder(str); | ||||
|     // new BackgroundColorSpan(Color.RED)背景高亮
 | ||||
|     // ForegroundColorSpan(Color.RED) 字体高亮
 | ||||
|     style.setSpan(new ForegroundColorSpan(color), start, start + highLightStr.length(), | ||||
|         Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); | ||||
|     return style; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 字符串转hashcode | ||||
|    */ | ||||
|   public static int keyToHashCode(String str) { | ||||
|     int total = 0; | ||||
|     for (int i = 0; i < str.length(); i++) { | ||||
|       char ch = str.charAt(i); | ||||
|       if (ch == '-') ch = (char) 28; // does not contain the same last 5 bits as any letter
 | ||||
|       if (ch == '\'') ch = (char) 29; // nor this
 | ||||
|       total = (total * 33) + (ch & 0x1F); | ||||
|     } | ||||
|     return total; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 字符串转dbouble | ||||
|    */ | ||||
|   public static double strToDouble(String str) { | ||||
|     // double d = Double.parseDouble(str);
 | ||||
| 
 | ||||
| 		/* 以下代码处理精度问题 */ | ||||
|     BigDecimal bDeci = new BigDecimal(str); | ||||
|     // BigDecimal chushu =new BigDecimal(100000000);
 | ||||
|     // BigDecimal result =bDeci.divide(chushu,new
 | ||||
|     // MathContext(4));//MathConText(4)表示结果精确4位!
 | ||||
|     // return result.doubleValue() * 100000000;
 | ||||
|     return bDeci.doubleValue(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 将普通字符串转换为16位进制字符串 | ||||
|    */ | ||||
|   public static String bytesToHexString(byte[] src) { | ||||
|     StringBuilder stringBuilder = new StringBuilder("0x"); | ||||
|     if (src == null || src.length <= 0) { | ||||
|       return null; | ||||
|     } | ||||
|     char[] buffer = new char[2]; | ||||
|     for (byte aSrc : src) { | ||||
|       buffer[0] = Character.forDigit((aSrc >>> 4) & 0x0F, 16); | ||||
|       buffer[1] = Character.forDigit(aSrc & 0x0F, 16); | ||||
|       stringBuilder.append(buffer); | ||||
|     } | ||||
|     return stringBuilder.toString(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 把字符串长度加满16位 | ||||
|    * | ||||
|    * @return 16位长度的字符串 | ||||
|    */ | ||||
|   public static String addStrLenTo16(String str) { | ||||
|     //由于汉字的特殊性,长度要用byte来判断
 | ||||
|     for (int i = str.getBytes().length; i < 16; i++) { | ||||
|       str += '\0'; | ||||
|     } | ||||
|     return str; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取对象名 | ||||
|    * | ||||
|    * @param obj 对象 | ||||
|    * @return 对象名 | ||||
|    */ | ||||
|   public static String getClassName(Object obj) { | ||||
|     String arrays[] = obj.getClass().getName().split("\\."); | ||||
|     return arrays[arrays.length - 1]; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,245 @@ | ||||
| package com.arialyy.frame.util; | ||||
| 
 | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import java.io.BufferedReader; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.text.DecimalFormat; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| /** | ||||
|  * 文本处理工具 | ||||
|  */ | ||||
| public class TextUtil { | ||||
|   private TextUtil() { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化字符 | ||||
|    */ | ||||
|   public static String decimalFormat(Number scr, String format) { | ||||
|     return new DecimalFormat(format).format(scr); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 替换字符号(不带空格) | ||||
|    */ | ||||
|   public static String replaceSymbol(String str) { | ||||
|     String dest = ""; | ||||
|     if (str != null) { | ||||
|       // Pattern p = Pattern.compile("\\s*|\t|\r|\n");
 | ||||
|       Pattern p = Pattern.compile("\t|\r|\n"); | ||||
|       Matcher m = p.matcher(str); | ||||
|       dest = m.replaceAll(""); | ||||
|     } | ||||
|     return dest; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 首字母大写 | ||||
|    */ | ||||
|   public static String firstUpperCase(String str) { | ||||
|     if (android.text.TextUtils.isEmpty(str)) { | ||||
|       return null; | ||||
|     } | ||||
|     return str.replaceFirst(str.substring(0, 1), str.substring(0, 1).toUpperCase()); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从文本中读取数据,返回成List对象 | ||||
|    */ | ||||
|   public static List<String> getTextToList(File file) { | ||||
|     FileInputStream fileInputStream = null; | ||||
|     InputStreamReader inputStreamReader = null; | ||||
|     BufferedReader bufferedReader = null; | ||||
|     List<String> list = new ArrayList<String>(); | ||||
|     try { | ||||
|       fileInputStream = new FileInputStream(file); | ||||
|       inputStreamReader = new InputStreamReader(fileInputStream); | ||||
|       bufferedReader = new BufferedReader(inputStreamReader); | ||||
|       String text; | ||||
|       while ((text = bufferedReader.readLine()) != null) { | ||||
|         list.add(text); | ||||
|       } | ||||
|     } catch (FileNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } finally { | ||||
|       try { | ||||
|         if (fileInputStream != null) { | ||||
|           fileInputStream.close(); | ||||
|         } | ||||
|         if (inputStreamReader != null) { | ||||
|           inputStreamReader.close(); | ||||
|         } | ||||
|         if (bufferedReader != null) { | ||||
|           bufferedReader.close(); | ||||
|         } | ||||
|       } catch (IOException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|     } | ||||
|     return list; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 从文本中读取数据,返回成List对象 | ||||
|    */ | ||||
|   public static List<String> getTextToList(InputStream inputStream) { | ||||
|     InputStreamReader inputStreamReader = null; | ||||
|     BufferedReader bufferedReader = null; | ||||
|     List<String> list = new ArrayList<String>(); | ||||
|     try { | ||||
|       inputStreamReader = new InputStreamReader(inputStream); | ||||
|       bufferedReader = new BufferedReader(inputStreamReader); | ||||
|       String text; | ||||
|       while ((text = bufferedReader.readLine()) != null) { | ||||
|         list.add(text); | ||||
|       } | ||||
|     } catch (FileNotFoundException e) { | ||||
|       e.printStackTrace(); | ||||
|     } catch (IOException e) { | ||||
|       e.printStackTrace(); | ||||
|     } finally { | ||||
|       try { | ||||
|         if (inputStreamReader != null) { | ||||
|           inputStreamReader.close(); | ||||
|         } | ||||
|         if (bufferedReader != null) { | ||||
|           bufferedReader.close(); | ||||
|         } | ||||
|       } catch (IOException e) { | ||||
|         e.printStackTrace(); | ||||
|       } | ||||
|     } | ||||
|     return list; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 判断一个数是否是整数 | ||||
|    */ | ||||
|   public static boolean isInteger(String numStr) { | ||||
|     try { | ||||
|       double parseDouble = Double.parseDouble(numStr); | ||||
|       return parseDouble % 1 == 0; | ||||
|     } catch (Exception exception) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 判断一个数是否是大于0的数 | ||||
|    */ | ||||
|   public static boolean isPositiveInteger(String numStr) { | ||||
|     if (isInteger(numStr)) { | ||||
|       double parseDouble = Double.parseDouble(numStr); | ||||
|       if (parseDouble > 0) { | ||||
|         return true; | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化数据 | ||||
|    * | ||||
|    * @param value 需要转换的值 | ||||
|    * @param pattern 小数位数 | ||||
|    */ | ||||
|   public static String decimalFormat(double value, String pattern) { | ||||
|     DecimalFormat df = new DecimalFormat(pattern); | ||||
|     return df.format(value); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化数据 | ||||
|    * | ||||
|    * @param value 需要转换的值 | ||||
|    * @param pattern 小数位数 | ||||
|    */ | ||||
|   public static String decimalFormat(String value, String pattern) { | ||||
|     DecimalFormat df = new DecimalFormat(pattern); | ||||
|     return df.format(Double.parseDouble(value)); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化数据 | ||||
|    */ | ||||
|   public static String decimalFormat(double value, int scale) { | ||||
|     return decimalFormat(value, getScalePattern(scale)); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 格式化数据 | ||||
|    */ | ||||
|   public static String decimalFormat(String value, int scale) { | ||||
|     return decimalFormat(value, getScalePattern(scale)); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回小数位数的匹配 | ||||
|    */ | ||||
|   private static String getScalePattern(int scale) { | ||||
|     StringBuffer sb = new StringBuffer("#0."); | ||||
|     if (scale <= 0) { | ||||
|       sb = new StringBuffer("#"); | ||||
|     } | ||||
|     for (int i = 0; i < scale; ++i) { | ||||
|       sb.append("0"); | ||||
|     } | ||||
|     return sb.toString(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回TextView的值,没有或者null返回0 | ||||
|    */ | ||||
|   public static String getViewText(TextView view) { | ||||
|     if (view == null) { | ||||
|       return "0"; | ||||
|     } | ||||
|     boolean empty = android.text.TextUtils.isEmpty(view.getText().toString()); | ||||
|     return empty ? "0" : view.getText().toString(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 替换字符串 | ||||
|    */ | ||||
|   public static String replace(String source, int index, String before, String after) { | ||||
|     Matcher matcher = Pattern.compile(before).matcher(source); | ||||
|     for (int counter = 0; matcher.find(); counter++) { | ||||
|       if (counter == index) { | ||||
|         return source.substring(0, matcher.start()) + after + source.substring(matcher.end(), | ||||
|             source.length()); | ||||
|       } | ||||
|     } | ||||
|     return source; | ||||
|   } | ||||
| 
 | ||||
|   public static String JsonToString(String src) { | ||||
|     if ("{}".equals(src) || "[]".equals(src)) { | ||||
|       return ""; | ||||
|     } | ||||
|     return src; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 去掉空格和特殊字符 | ||||
|    */ | ||||
|   public static String trimString(String str) { | ||||
|     if (android.text.TextUtils.isEmpty(str)) { | ||||
|       return ""; | ||||
|     } else { | ||||
|       return str.trim(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,200 @@ | ||||
| package com.arialyy.frame.util.show; | ||||
| 
 | ||||
| import android.util.Log; | ||||
| import com.arialyy.frame.util.CalendarUtils; | ||||
| import java.io.File; | ||||
| import java.io.FileWriter; | ||||
| import java.io.PrintWriter; | ||||
| import org.json.JSONArray; | ||||
| import org.json.JSONException; | ||||
| import org.json.JSONObject; | ||||
| 
 | ||||
| /** | ||||
|  * Created by “AriaLyy@outlook.com” on 2015/4/1. | ||||
|  * 写入文件的log,由于使用到反射和文件流的操作,建议在需要的地方才去使用 | ||||
|  */ | ||||
| public class FL { | ||||
|   public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化
 | ||||
|   public static String PATH = "/GameBar2/log/AriaFrameLog__";    //log路径
 | ||||
|   static String LINE_SEPARATOR = System.getProperty("line.separator"); //等价于"\n\r",唯一的作用是能装逼
 | ||||
|   static int JSON_INDENT = 4; | ||||
| 
 | ||||
|   private static String printLine(String tag, boolean isTop) { | ||||
|     String top = | ||||
|         "╔══════════════════════════════════════════ JSON ═══════════════════════════════════════"; | ||||
|     String bottom = | ||||
|         "╚═══════════════════════════════════════════════════════════════════════════════════════"; | ||||
|     if (isTop) { | ||||
|       Log.d(tag, top); | ||||
|       return top; | ||||
|     } else { | ||||
|       Log.d(tag, bottom); | ||||
|       return bottom; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 打印JSON | ||||
|    */ | ||||
|   public static void j(String tag, String jsonStr) { | ||||
|     if (isDebug) { | ||||
|       String message; | ||||
|       try { | ||||
|         if (jsonStr.startsWith("{")) { | ||||
|           JSONObject jsonObject = new JSONObject(jsonStr); | ||||
|           message = jsonObject.toString(JSON_INDENT); //这个是核心方法
 | ||||
|         } else if (jsonStr.startsWith("[")) { | ||||
|           JSONArray jsonArray = new JSONArray(jsonStr); | ||||
|           message = jsonArray.toString(JSON_INDENT); | ||||
|         } else { | ||||
|           message = jsonStr; | ||||
|         } | ||||
|       } catch (JSONException e) { | ||||
|         message = jsonStr; | ||||
|       } | ||||
| 
 | ||||
|       message = LINE_SEPARATOR + message; | ||||
|       String temp = "\n" + printLine(tag, true) + "\n"; | ||||
|       String[] lines = message.split(LINE_SEPARATOR); | ||||
|       for (String line : lines) { | ||||
|         temp += "║ " + line + "\n"; | ||||
|         Log.d(tag, "║ " + line); | ||||
|       } | ||||
|       temp += printLine(tag, false); | ||||
|       writeLogToFile(tag, temp); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // 下面四个是默认tag的函数
 | ||||
|   public static void i(Object obj, String msg) { | ||||
|     String TAG = getTag(obj); | ||||
|     if (isDebug) { | ||||
|       Log.i(TAG, msg); | ||||
|       writeLogToFile(TAG, msg); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public static void d(Object obj, String msg) { | ||||
|     String TAG = getTag(obj); | ||||
|     if (isDebug) { | ||||
|       Log.d(TAG, msg); | ||||
|       writeLogToFile(TAG, msg); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public static void e(Object obj, String msg) { | ||||
|     String TAG = getTag(obj); | ||||
|     if (isDebug) { | ||||
|       Log.e(TAG, msg); | ||||
|       writeLogToFile(TAG, msg); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public static void v(Object obj, String msg) { | ||||
|     String TAG = getTag(obj); | ||||
|     if (isDebug) { | ||||
|       Log.v(TAG, msg); | ||||
|       writeLogToFile(TAG, msg); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public static void i(String TAG, String msg) { | ||||
|     if (isDebug) { | ||||
|       Log.i(TAG, msg); | ||||
|       writeLogToFile(TAG, msg); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public static void d(String TAG, String msg) { | ||||
|     if (isDebug) { | ||||
|       Log.d(TAG, msg); | ||||
|       writeLogToFile(TAG, msg); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public static void e(String TAG, String msg) { | ||||
|     if (isDebug) { | ||||
|       Log.e(TAG, msg); | ||||
|       writeLogToFile(TAG, msg); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public static void v(String TAG, String msg) { | ||||
|     if (isDebug) { | ||||
|       Log.v(TAG, msg); | ||||
|       writeLogToFile(TAG, msg); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 获取类名 | ||||
|    */ | ||||
|   private static String getTag(Object object) { | ||||
|     Class<?> cls = object.getClass(); | ||||
|     String tag = cls.getName(); | ||||
|     String arrays[] = tag.split("\\."); | ||||
|     tag = arrays[arrays.length - 1]; | ||||
|     return tag; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 返回日志路径 | ||||
|    */ | ||||
|   public static String getLogPath() { | ||||
|     String path = PATH + CalendarUtils.getData() + ".txt"; | ||||
|     return android.os.Environment.getExternalStorageDirectory().getPath() + File.separator + path; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 把日志记录到文件 | ||||
|    */ | ||||
|   private static int writeLogToFile(String tag, String message) { | ||||
|     StringBuffer stringBuffer = new StringBuffer(); | ||||
|     stringBuffer.append(CalendarUtils.getNowDataTime()); | ||||
|     stringBuffer.append("    "); | ||||
|     stringBuffer.append(tag); | ||||
|     stringBuffer.append("    "); | ||||
|     stringBuffer.append(message); | ||||
|     stringBuffer.append("\n"); | ||||
|     PrintWriter writer = null; | ||||
|     try { | ||||
|       writer = new PrintWriter(new FileWriter(getLogPath(), true)); | ||||
|       writer.append(stringBuffer); | ||||
|       writer.flush(); | ||||
|     } catch (Exception e) { | ||||
|       e.printStackTrace(); | ||||
|     } finally { | ||||
|       if (writer != null) { | ||||
|         writer.close(); | ||||
|       } | ||||
|     } | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 将异常信息转换为字符串 | ||||
|    */ | ||||
|   public static String getExceptionString(Throwable ex) { | ||||
|     StringBuilder err = new StringBuilder(); | ||||
|     err.append("ExceptionDetailed:\n"); | ||||
|     err.append("====================Exception Info====================\n"); | ||||
|     err.append(ex.toString()); | ||||
|     err.append("\n"); | ||||
|     StackTraceElement[] stack = ex.getStackTrace(); | ||||
|     for (StackTraceElement stackTraceElement : stack) { | ||||
|       err.append(stackTraceElement.toString()).append("\n"); | ||||
|     } | ||||
|     Throwable cause = ex.getCause(); | ||||
|     if (cause != null) { | ||||
|       err.append("【Caused by】: "); | ||||
|       err.append(cause.toString()); | ||||
|       err.append("\n"); | ||||
|       StackTraceElement[] stackTrace = cause.getStackTrace(); | ||||
|       for (StackTraceElement stackTraceElement : stackTrace) { | ||||
|         err.append(stackTraceElement.toString()).append("\n"); | ||||
|       } | ||||
|     } | ||||
|     err.append("==================================================="); | ||||
|     return err.toString(); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,265 @@ | ||||
| package com.arialyy.frame.util.show; | ||||
| 
 | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import org.json.JSONArray; | ||||
| import org.json.JSONException; | ||||
| import org.json.JSONObject; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| 
 | ||||
| /** | ||||
|  * Created by Lyy on 2015/4/1. | ||||
|  * 普通的Log管理类 | ||||
|  */ | ||||
| public class L { | ||||
|   /** | ||||
|    * Drawing toolbox | ||||
|    */ | ||||
|   private static final char TOP_LEFT_CORNER = '╔'; | ||||
|   private static final char BOTTOM_LEFT_CORNER = '╚'; | ||||
|   private static final char MIDDLE_CORNER = '╟'; | ||||
|   private static final char HORIZONTAL_DOUBLE_LINE = '║'; | ||||
|   private static final String DOUBLE_DIVIDER = "════════════════════════════════════════════"; | ||||
|   private static final String SINGLE_DIVIDER = "────────────────────────────────────────────"; | ||||
|   private static final String TOP_BORDER = TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER; | ||||
|   private static final String BOTTOM_BORDER = BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER; | ||||
|   private static final String MIDDLE_BORDER = MIDDLE_CORNER + SINGLE_DIVIDER + SINGLE_DIVIDER; | ||||
|   private static final char I = 'I', W = 'W', D = 'D', E = 'E', V = 'V', A = 'A', M = 'M'; | ||||
| 
 | ||||
|   static String LINE_SEPARATOR = System.getProperty("line.separator"); //等价于"\n\r",唯一的作用是能装逼
 | ||||
|   static int JSON_INDENT = 4; | ||||
| 
 | ||||
|   private L() { | ||||
|         /* cannot be instantiated */ | ||||
|     throw new UnsupportedOperationException("cannot be instantiated"); | ||||
|   } | ||||
| 
 | ||||
|   public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化
 | ||||
|   private static final String TAG = "lyy"; | ||||
| 
 | ||||
|   /** | ||||
|    * map to str | ||||
|    */ | ||||
|   public static String m2s(Map map) { | ||||
|     if (isDebug) { | ||||
|       if (map == null) { | ||||
|         return ""; | ||||
|       } | ||||
|       StringBuilder sb = new StringBuilder(); | ||||
|       Set set = map.entrySet(); | ||||
|       for (Object aSet : set) { | ||||
|         Map.Entry entry = (Map.Entry) aSet; | ||||
|         sb.append(entry.getValue()); | ||||
|       } | ||||
|       return sb.toString(); | ||||
|     } | ||||
|     return ""; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 打印MAp | ||||
|    */ | ||||
|   public static void m(Map map) { | ||||
|     if (isDebug) { | ||||
|       Set set = map.entrySet(); | ||||
|       if (set.size() < 1) { | ||||
|         printLog(D, "[]"); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       int i = 0; | ||||
|       String[] s = new String[set.size()]; | ||||
|       for (Object aSet : set) { | ||||
|         Map.Entry entry = (Map.Entry) aSet; | ||||
|         s[i] = entry.getKey() + " = " + entry.getValue() + ",\n"; | ||||
|         i++; | ||||
|       } | ||||
|       printLog(V, s); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 打印JSON | ||||
|    */ | ||||
|   public static void j(String jsonStr) { | ||||
|     if (isDebug) { | ||||
|       String message; | ||||
|       try { | ||||
|         if (jsonStr.startsWith("{")) { | ||||
|           JSONObject jsonObject = new JSONObject(jsonStr); | ||||
|           message = jsonObject.toString(JSON_INDENT); //这个是核心方法
 | ||||
|         } else if (jsonStr.startsWith("[")) { | ||||
|           JSONArray jsonArray = new JSONArray(jsonStr); | ||||
|           message = jsonArray.toString(JSON_INDENT); | ||||
|         } else { | ||||
|           message = jsonStr; | ||||
|         } | ||||
|       } catch (JSONException e) { | ||||
|         message = jsonStr; | ||||
|       } | ||||
| 
 | ||||
|       message = LINE_SEPARATOR + message; | ||||
|       String[] lines = message.split(LINE_SEPARATOR); | ||||
|       printLog(D, lines); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // 下面四个是默认tag的函数
 | ||||
|   public static void i(String... msg) { | ||||
|     if (isDebug) printLog(I, msg); | ||||
|   } | ||||
| 
 | ||||
|   public static void d(String... msg) { | ||||
|     if (isDebug) printLog(D, msg); | ||||
|   } | ||||
| 
 | ||||
|   public static void w(String... msg) { | ||||
|     if (isDebug) printLog(W, msg); | ||||
|   } | ||||
| 
 | ||||
|   public static void e(String... msg) { | ||||
|     if (isDebug) printLog(E, msg); | ||||
|   } | ||||
| 
 | ||||
|   public static void e(Throwable tr) { | ||||
|     if (isDebug) printLog(E, FL.getExceptionString(tr)); | ||||
|   } | ||||
| 
 | ||||
|   public static void v(String... msg) { | ||||
|     if (isDebug) printLog(V, msg); | ||||
|   } | ||||
| 
 | ||||
|   // 下面是传入自定义tag的函数
 | ||||
|   public static void i(String tag, String msg) { | ||||
|     if (isDebug) Log.i(tag, msg); | ||||
|   } | ||||
| 
 | ||||
|   public static void d(String tag, String msg) { | ||||
|     if (isDebug) Log.d(tag, msg); | ||||
|   } | ||||
| 
 | ||||
|   public static void w(String tag, String msg) { | ||||
|     if (isDebug) Log.w(tag, msg); | ||||
|   } | ||||
| 
 | ||||
|   public static void e(String tag, String msg) { | ||||
|     if (isDebug) Log.e(tag, msg); | ||||
|   } | ||||
| 
 | ||||
|   public static void v(String tag, String msg) { | ||||
|     if (isDebug) Log.v(tag, msg); | ||||
|   } | ||||
| 
 | ||||
|   //带异常的
 | ||||
|   public static void i(String tag, String msg, Throwable tr) { | ||||
|     if (isDebug) Log.i(tag, msg, tr); | ||||
|   } | ||||
| 
 | ||||
|   public static void d(String tag, String msg, Throwable tr) { | ||||
|     if (isDebug) Log.d(tag, msg, tr); | ||||
|   } | ||||
| 
 | ||||
|   public static void w(String tag, String msg, Throwable tr) { | ||||
|     if (isDebug) Log.w(tag, msg, tr); | ||||
|   } | ||||
| 
 | ||||
|   public static void e(String tag, String msg, Throwable tr) { | ||||
|     if (isDebug) Log.e(tag, msg, tr); | ||||
|   } | ||||
| 
 | ||||
|   public static void v(String tag, String msg, Throwable tr) { | ||||
|     if (isDebug) Log.v(tag, msg, tr); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 统一打印 | ||||
|    */ | ||||
|   private static void printHunk(char type, String str) { | ||||
|     switch (type) { | ||||
|       case I: | ||||
|         Log.i(TAG, str); | ||||
|         break; | ||||
|       case D: | ||||
|         Log.d(TAG, str); | ||||
|         break; | ||||
|       case E: | ||||
|         Log.e(TAG, str); | ||||
|         break; | ||||
|       case V: | ||||
|         Log.v(TAG, str); | ||||
|         break; | ||||
|       case A: | ||||
|         Log.wtf(TAG, str); | ||||
|         break; | ||||
|       case W: | ||||
|         Log.w(TAG, str); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 打印头部信息 | ||||
|    */ | ||||
|   private static void printHead(char type) { | ||||
|     printHunk(type, TOP_BORDER); | ||||
|     printHunk(type, HORIZONTAL_DOUBLE_LINE + "   Thread:"); | ||||
|     printHunk(type, HORIZONTAL_DOUBLE_LINE + "   " + Thread.currentThread().getName()); | ||||
|     printHunk(type, MIDDLE_BORDER); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 打印Log被调用的位置 | ||||
|    */ | ||||
|   private static void printLocation(char type, String... msg) { | ||||
|     StackTraceElement[] stack = Thread.currentThread().getStackTrace(); | ||||
|     int i = 0; | ||||
|     for (StackTraceElement e : stack) { | ||||
|       String name = e.getClassName(); | ||||
|       if (!name.equals(L.class.getName())) { | ||||
|         i++; | ||||
|       } else { | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     i += 3; | ||||
|     String className = stack[i].getFileName(); | ||||
|     String methodName = stack[i].getMethodName(); | ||||
|     int lineNumber = stack[i].getLineNumber(); | ||||
|     StringBuilder sb = new StringBuilder(); | ||||
|     printHunk(type, HORIZONTAL_DOUBLE_LINE + "   Location:"); | ||||
|     sb.append(HORIZONTAL_DOUBLE_LINE) | ||||
|         .append("   (") | ||||
|         .append(className) | ||||
|         .append(":") | ||||
|         .append(lineNumber) | ||||
|         .append(")# ") | ||||
|         .append(methodName); | ||||
|     printHunk(type, sb.toString()); | ||||
|     printHunk(type, msg == null || msg.length == 0 ? BOTTOM_BORDER : MIDDLE_BORDER); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 打印消息 | ||||
|    */ | ||||
|   private static void printMsg(char type, String... msg) { | ||||
|     printHunk(type, HORIZONTAL_DOUBLE_LINE + "   msg:"); | ||||
|     for (String str : msg) { | ||||
|       printHunk(type, HORIZONTAL_DOUBLE_LINE + "   " + str); | ||||
|     } | ||||
|     printHunk(type, BOTTOM_BORDER); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 打印log | ||||
|    */ | ||||
|   private static void printLog(char type, String... msg) { | ||||
|     printHead(type); | ||||
|     printLocation(type, msg); | ||||
|     if (msg == null || msg.length == 0) { | ||||
|       return; | ||||
|     } | ||||
|     printMsg(type, msg); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,62 @@ | ||||
| package com.arialyy.frame.util.show; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
| /** | ||||
|  * Created by Lyy on 2015/4/1. | ||||
|  * Toast统一管理类 | ||||
|  */ | ||||
| public class T { | ||||
| 
 | ||||
|   private T() { | ||||
|     throw new UnsupportedOperationException("cannot be instantiated"); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 是否显示Tost | ||||
|    */ | ||||
|   public static boolean isShow = true; | ||||
| 
 | ||||
|   /** | ||||
|    * 短时间显示Toast | ||||
|    */ | ||||
|   public static void showShort(Context context, CharSequence message) { | ||||
|     if (isShow) Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 短时间显示Toast | ||||
|    */ | ||||
|   public static void showShort(Context context, int message) { | ||||
|     if (isShow) Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 长时间显示Toast | ||||
|    */ | ||||
|   public static void showLong(Context context, CharSequence message) { | ||||
|     if (isShow) Toast.makeText(context, message, Toast.LENGTH_LONG).show(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 长时间显示Toast | ||||
|    */ | ||||
|   public static void showLong(Context context, int message) { | ||||
|     if (isShow) Toast.makeText(context, message, Toast.LENGTH_LONG).show(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 自定义显示Toast时间 | ||||
|    */ | ||||
|   public static void show(Context context, CharSequence message, int duration) { | ||||
|     if (isShow) Toast.makeText(context, message, duration).show(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * 自定义显示Toast时间 | ||||
|    */ | ||||
|   public static void show(Context context, int message, int duration) { | ||||
|     if (isShow) Toast.makeText(context, message, duration).show(); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,15 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <selector xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|   <item android:state_pressed="true"> | ||||
|     <shape android:shape="rectangle"> | ||||
|       <solid android:color="#005bab"/> | ||||
|       <corners android:radius="30dp"/> | ||||
|     </shape> | ||||
|   </item> | ||||
|   <item android:state_pressed="false"> | ||||
|     <shape android:shape="rectangle"> | ||||
|       <solid android:color="#095389"/> | ||||
|       <corners android:radius="30dp"/> | ||||
|     </shape> | ||||
|   </item> | ||||
| </selector> | ||||
| @ -0,0 +1,62 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:background="@color/background_color" | ||||
|     > | ||||
| 
 | ||||
|   <LinearLayout | ||||
|       android:id="@+id/temp" | ||||
|       android:layout_width="match_parent" | ||||
|       android:layout_height="wrap_content" | ||||
|       android:layout_gravity="center_vertical" | ||||
|       android:orientation="vertical" | ||||
|       > | ||||
| 
 | ||||
|     <ProgressBar | ||||
|         android:id="@+id/pb" | ||||
|         android:layout_width="100dp" | ||||
|         android:layout_height="100dp" | ||||
|         android:layout_gravity="center" | ||||
|         android:visibility="gone" | ||||
|         /> | ||||
| 
 | ||||
|     <FrameLayout | ||||
|         android:id="@+id/error" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_gravity="center" | ||||
|         > | ||||
| 
 | ||||
|       <RelativeLayout | ||||
|           android:layout_width="match_parent" | ||||
|           android:layout_height="wrap_content" | ||||
|           > | ||||
| 
 | ||||
|         <TextView | ||||
|             android:id="@+id/hint" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:text="网络错误" | ||||
|             android:textColor="@android:color/black" | ||||
|             android:textSize="20sp" | ||||
|             /> | ||||
| 
 | ||||
|         <Button | ||||
|             android:id="@+id/bt" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="40dp" | ||||
|             android:layout_below="@+id/hint" | ||||
|             android:layout_centerInParent="true" | ||||
|             android:layout_marginTop="16dp" | ||||
|             android:background="@drawable/selector_green_bt" | ||||
|             android:text="刷新" | ||||
|             android:textColor="@android:color/white" | ||||
|             android:textSize="16sp" | ||||
|             /> | ||||
|       </RelativeLayout> | ||||
| 
 | ||||
|     </FrameLayout> | ||||
|   </LinearLayout> | ||||
| 
 | ||||
| </LinearLayout> | ||||
| @ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|   <color name="background_color">#E5E5E5</color> | ||||
|   <color name="white">#fff</color> | ||||
|   <color name="text_gray_color">#A5A5A5</color> | ||||
| </resources> | ||||
| @ -0,0 +1,3 @@ | ||||
| <resources> | ||||
|   <string name="app_name">Frame</string> | ||||
| </resources> | ||||
| @ -0,0 +1,15 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|   <!-- Base application theme. --> | ||||
|   <style name="AppTheme" parent="Theme.AppCompat.Light.Dialog.Alert"> | ||||
|     <!-- Customize your theme here. --> | ||||
|   </style> | ||||
|   <!--        <item name="android:windowBackground">@drawable/white_pop_normal_background</item> | ||||
| --> | ||||
|   <style name="MyDialog" parent="AppTheme"> | ||||
|     <item name="android:windowFrame">@null</item> | ||||
|     <item name="android:windowNoTitle">true</item> | ||||
|     <item name="android:windowIsFloating">true</item> | ||||
|     <item name="android:windowContentOverlay">@null</item> | ||||
|   </style> | ||||
| </resources> | ||||
| @ -1,12 +1,12 @@ | ||||
| apply plugin: 'bintray-release' | ||||
| apply plugin: 'com.novoda.bintray-release' | ||||
| publish { | ||||
|   artifactId = 'aria-core' | ||||
|   userOrg = rootProject.userOrg | ||||
|   groupId = rootProject.groupId | ||||
|   userOrg = rootProject.ext.userOrg | ||||
|   groupId = rootProject.ext.groupId | ||||
|   //  uploadName = rootProject.uploadName | ||||
|   uploadName = 'AriaApi' | ||||
|   publishVersion = rootProject.publishVersion | ||||
|   description = rootProject.description | ||||
|   website = rootProject.website | ||||
|   licences = rootProject.licences | ||||
|   publishVersion = rootProject.ext.publishVersion | ||||
|   desc = rootProject.ext.desc | ||||
|   website = rootProject.ext.website | ||||
|   licences = rootProject.ext.licences | ||||
| } | ||||
| @ -1,12 +1,12 @@ | ||||
| apply plugin: 'bintray-release' | ||||
| apply plugin: 'com.novoda.bintray-release' | ||||
| publish { | ||||
|   artifactId = 'aria-annotations' | ||||
|   userOrg = rootProject.userOrg | ||||
|   groupId = rootProject.groupId | ||||
|   userOrg = rootProject.ext.userOrg | ||||
|   groupId = rootProject.ext.groupId | ||||
|   //  uploadName = rootProject.uploadName | ||||
|   uploadName = 'AriaAnnotations' | ||||
|   publishVersion = rootProject.publishVersion | ||||
|   description = rootProject.description | ||||
|   website = rootProject.website | ||||
|   licences = rootProject.licences | ||||
|   publishVersion = rootProject.ext.publishVersion | ||||
|   desc = rootProject.ext.desc | ||||
|   website = rootProject.ext.website | ||||
|   licences = rootProject.ext.licences | ||||
| } | ||||
| @ -1,12 +1,12 @@ | ||||
| apply plugin: 'bintray-release' | ||||
| apply plugin: 'com.novoda.bintray-release' | ||||
| publish { | ||||
|   artifactId = 'aria-compiler' | ||||
|   userOrg = rootProject.userOrg | ||||
|   groupId = rootProject.groupId | ||||
|   userOrg = rootProject.ext.userOrg | ||||
|   groupId = rootProject.ext.groupId | ||||
|   //  uploadName = rootProject.uploadName | ||||
|   uploadName = 'AriaCompiler' | ||||
|   publishVersion = rootProject.publishVersion | ||||
|   description = rootProject.description | ||||
|   website = rootProject.website | ||||
|   licences = rootProject.licences | ||||
|   publishVersion = rootProject.ext.publishVersion | ||||
|   desc = rootProject.ext.desc | ||||
|   website = rootProject.ext.website | ||||
|   licences = rootProject.ext.licences | ||||
| } | ||||
| @ -1,11 +1,11 @@ | ||||
| apply plugin: 'bintray-release' | ||||
| apply plugin: 'com.novoda.bintray-release' | ||||
| publish { | ||||
|   artifactId = 'aria-ftp-plug' | ||||
|   userOrg = rootProject.userOrg | ||||
|   groupId = rootProject.groupId | ||||
|   userOrg = rootProject.ext.userOrg | ||||
|   groupId = rootProject.ext.groupId | ||||
|   uploadName = 'FtpPlug' | ||||
|   publishVersion = rootProject.publishVersion | ||||
|   description = rootProject.description | ||||
|   website = rootProject.website | ||||
|   licences = rootProject.licences | ||||
|   publishVersion = rootProject.ext.publishVersion | ||||
|   desc = rootProject.ext.desc | ||||
|   website = rootProject.ext.website | ||||
|   licences = rootProject.ext.licences | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
					Loading…
					
					
				
		Reference in new issue