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