laoyuyu 6 years ago
parent d8a14c0086
commit 0f9f2577b8
  1. 4
      AppFrame/.gitignore
  2. 201
      AppFrame/LICENSE
  3. 39
      AppFrame/build.gradle
  4. 168
      AppFrame/jcenter.gradle
  5. 17
      AppFrame/proguard-rules.pro
  6. 14
      AppFrame/src/main/AndroidManifest.xml
  7. 367
      AppFrame/src/main/java/com/arialyy/frame/cache/AbsCache.java
  8. 81
      AppFrame/src/main/java/com/arialyy/frame/cache/CacheHelp.java
  9. 56
      AppFrame/src/main/java/com/arialyy/frame/cache/CacheObj.java
  10. 37
      AppFrame/src/main/java/com/arialyy/frame/cache/CacheParam.java
  11. 262
      AppFrame/src/main/java/com/arialyy/frame/cache/CacheUtil.java
  12. 951
      AppFrame/src/main/java/com/arialyy/frame/cache/diskcache/DiskLruCache.java
  13. 77
      AppFrame/src/main/java/com/arialyy/frame/cache/diskcache/DiskLruCacheUtil.java
  14. 194
      AppFrame/src/main/java/com/arialyy/frame/cache/diskcache/StrictLineReader.java
  15. 242
      AppFrame/src/main/java/com/arialyy/frame/core/AbsActivity.java
  16. 112
      AppFrame/src/main/java/com/arialyy/frame/core/AbsAlertDialog.java
  17. 96
      AppFrame/src/main/java/com/arialyy/frame/core/AbsDialog.java
  18. 160
      AppFrame/src/main/java/com/arialyy/frame/core/AbsDialogFragment.java
  19. 274
      AppFrame/src/main/java/com/arialyy/frame/core/AbsFragment.java
  20. 203
      AppFrame/src/main/java/com/arialyy/frame/core/AbsFrame.java
  21. 133
      AppFrame/src/main/java/com/arialyy/frame/core/AbsPopupWindow.java
  22. 60
      AppFrame/src/main/java/com/arialyy/frame/core/BindingFactory.java
  23. 167
      AppFrame/src/main/java/com/arialyy/frame/core/CrashHandler.java
  24. 40
      AppFrame/src/main/java/com/arialyy/frame/core/DialogSimpleModule.java
  25. 68
      AppFrame/src/main/java/com/arialyy/frame/core/ModuleFactory.java
  26. 81
      AppFrame/src/main/java/com/arialyy/frame/core/NotifyHelp.java
  27. 70
      AppFrame/src/main/java/com/arialyy/frame/core/PermissionHelp.java
  28. 339
      AppFrame/src/main/java/com/arialyy/frame/http/HttpUtil.java
  29. 41
      AppFrame/src/main/java/com/arialyy/frame/http/WebApiModule.java
  30. 39
      AppFrame/src/main/java/com/arialyy/frame/http/inf/IRequest.java
  31. 16
      AppFrame/src/main/java/com/arialyy/frame/http/inf/IResponse.java
  32. 143
      AppFrame/src/main/java/com/arialyy/frame/module/AbsModule.java
  33. 112
      AppFrame/src/main/java/com/arialyy/frame/module/IOCProxy.java
  34. 61
      AppFrame/src/main/java/com/arialyy/frame/module/ModuleFactory.java
  35. 31
      AppFrame/src/main/java/com/arialyy/frame/module/inf/ModuleListener.java
  36. 14
      AppFrame/src/main/java/com/arialyy/frame/permission/OnPermissionCallback.java
  37. 143
      AppFrame/src/main/java/com/arialyy/frame/permission/PermissionManager.java
  38. 201
      AppFrame/src/main/java/com/arialyy/frame/permission/PermissionUtil.java
  39. 74
      AppFrame/src/main/java/com/arialyy/frame/temp/AbsTempView.java
  40. 34
      AppFrame/src/main/java/com/arialyy/frame/temp/ITempView.java
  41. 10
      AppFrame/src/main/java/com/arialyy/frame/temp/OnTempBtClickListener.java
  42. 60
      AppFrame/src/main/java/com/arialyy/frame/temp/TempView.java
  43. 156
      AppFrame/src/main/java/com/arialyy/frame/util/AESEncryption.java
  44. 691
      AppFrame/src/main/java/com/arialyy/frame/util/AndroidUtils.java
  45. 90
      AppFrame/src/main/java/com/arialyy/frame/util/AndroidVersionUtil.java
  46. 82
      AppFrame/src/main/java/com/arialyy/frame/util/AppSigning.java
  47. 135
      AppFrame/src/main/java/com/arialyy/frame/util/AppUtils.java
  48. 299
      AppFrame/src/main/java/com/arialyy/frame/util/CalendarUtils.java
  49. 55
      AppFrame/src/main/java/com/arialyy/frame/util/DensityUtils.java
  50. 88
      AppFrame/src/main/java/com/arialyy/frame/util/DrawableUtil.java
  51. 520
      AppFrame/src/main/java/com/arialyy/frame/util/FileUtil.java
  52. 37
      AppFrame/src/main/java/com/arialyy/frame/util/KeyBoardUtils.java
  53. 47
      AppFrame/src/main/java/com/arialyy/frame/util/MathUtil.java
  54. 146
      AppFrame/src/main/java/com/arialyy/frame/util/NetUtils.java
  55. 224
      AppFrame/src/main/java/com/arialyy/frame/util/NinePatchBitmapFactory.java
  56. 49
      AppFrame/src/main/java/com/arialyy/frame/util/ObjUtil.java
  57. 150
      AppFrame/src/main/java/com/arialyy/frame/util/ReflectionUtil.java
  58. 95
      AppFrame/src/main/java/com/arialyy/frame/util/RegularExpression.java
  59. 208
      AppFrame/src/main/java/com/arialyy/frame/util/ScreenUtil.java
  60. 145
      AppFrame/src/main/java/com/arialyy/frame/util/SharePreUtil.java
  61. 212
      AppFrame/src/main/java/com/arialyy/frame/util/ShellUtils.java
  62. 23
      AppFrame/src/main/java/com/arialyy/frame/util/StreamUtil.java
  63. 328
      AppFrame/src/main/java/com/arialyy/frame/util/StringUtil.java
  64. 245
      AppFrame/src/main/java/com/arialyy/frame/util/TextUtil.java
  65. 200
      AppFrame/src/main/java/com/arialyy/frame/util/show/FL.java
  66. 265
      AppFrame/src/main/java/com/arialyy/frame/util/show/L.java
  67. 62
      AppFrame/src/main/java/com/arialyy/frame/util/show/T.java
  68. 15
      AppFrame/src/main/res/drawable/selector_green_bt.xml
  69. 62
      AppFrame/src/main/res/layout/layout_error_temp.xml
  70. 6
      AppFrame/src/main/res/values/color.xml
  71. 3
      AppFrame/src/main/res/values/strings.xml
  72. 15
      AppFrame/src/main/res/values/style.xml
  73. 14
      Aria/bintray-release.gradle
  74. 18
      Aria/build.gradle
  75. 4
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  76. 16
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/AbsFtpInfoThread.java
  77. 12
      Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java
  78. 39
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java
  79. 2
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  80. 4
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
  81. 3
      Aria/src/main/java/com/arialyy/aria/core/download/group/AbsGroupUtil.java
  82. 1
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java
  83. 14
      AriaAnnotations/bintray-release.gradle
  84. 24
      AriaAnnotations/src/main/java/com/arialyy/annotations/Download.java
  85. 22
      AriaAnnotations/src/main/java/com/arialyy/annotations/DownloadGroup.java
  86. 22
      AriaAnnotations/src/main/java/com/arialyy/annotations/Upload.java
  87. 14
      AriaCompiler/bintray-release.gradle
  88. 10
      AriaCompiler/build.gradle
  89. 14
      AriaFtpPlug/bintray-release.gradle
  90. 2
      AriaFtpPlug/build.gradle
  91. 7
      DEV_LOG.md
  92. 8
      README.md
  93. 28
      app/build.gradle
  94. 2
      app/gradle.properties
  95. 19
      app/src/main/java/com/arialyy/simple/MainActivity.java
  96. 11
      app/src/main/java/com/arialyy/simple/base/BaseActivity.java
  97. 15
      app/src/main/java/com/arialyy/simple/base/BaseApplication.java
  98. 3
      app/src/main/java/com/arialyy/simple/base/adapter/AbsHolder.java
  99. 2
      app/src/main/java/com/arialyy/simple/base/adapter/AbsRVAdapter.java
  100. 13
      app/src/main/java/com/arialyy/simple/common/MsgDialog.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -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 只能是ActivityFragment 的子类及其衍生类
*/
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 只能是ActivityFragment 的子类及其衍生类
*/
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系统版本是否在JellyBeanAndroid4.1或android4.1以上
*/
public static boolean hasJellyBean() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
}
/**
* 当前android系统版本是否在KitKatAndroid4.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 小于0srcData 小于 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 { publish {
artifactId = 'aria-core' artifactId = 'aria-core'
userOrg = rootProject.userOrg userOrg = rootProject.ext.userOrg
groupId = rootProject.groupId groupId = rootProject.ext.groupId
// uploadName = rootProject.uploadName // uploadName = rootProject.uploadName
uploadName = 'AriaApi' uploadName = 'AriaApi'
publishVersion = rootProject.publishVersion publishVersion = rootProject.ext.publishVersion
description = rootProject.description desc = rootProject.ext.desc
website = rootProject.website website = rootProject.ext.website
licences = rootProject.licences licences = rootProject.ext.licences
} }

@ -1,12 +1,12 @@
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
android { android {
compileSdkVersion 23 compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion '26.0.2' buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig { defaultConfig {
minSdkVersion 9 minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion 23 targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 329 versionCode 329
versionName "3.2.9" versionName "3.2.9"
} }
@ -22,11 +22,11 @@ android {
} }
dependencies { dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1' implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
compile project(':AriaAnnotations') api project(':AriaAnnotations')
compile 'com.arialyy.aria:aria-ftp-plug:1.0.4' // api 'com.arialyy.aria:aria-ftp-plug:1.0.4' //
// compile project(':AriaFtpPlug') // compile project(':AriaFtpPlug')
} }

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.common; package com.arialyy.aria.core.common;
import android.net.TrafficStats;
import android.os.Process; import android.os.Process;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.config.BaseTaskConfig; import com.arialyy.aria.core.config.BaseTaskConfig;
@ -36,6 +37,7 @@ import com.arialyy.aria.util.NetUtils;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -98,6 +100,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
isNotNetRetry = mAridManager.getAppConfig().isNotNetRetry(); isNotNetRetry = mAridManager.getAppConfig().isNotNetRetry();
} }
/** /**
* 设置线程是否中断 * 设置线程是否中断
* *
@ -515,6 +518,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
@Override public AbsThreadTask call() throws Exception { @Override public AbsThreadTask call() throws Exception {
isInterrupted = false; isInterrupted = false;
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
TrafficStats.setThreadStatsTag(UUID.randomUUID().toString().hashCode());
return this; return this;
} }
} }

@ -15,13 +15,16 @@
*/ */
package com.arialyy.aria.core.common.ftp; package com.arialyy.aria.core.common.ftp;
import android.net.TrafficStats;
import android.os.Process; import android.os.Process;
import android.text.TextUtils; import android.text.TextUtils;
import aria.apache.commons.net.ftp.FTP; import aria.apache.commons.net.ftp.FTP;
import aria.apache.commons.net.ftp.FTPClient; import aria.apache.commons.net.ftp.FTPClient;
import aria.apache.commons.net.ftp.FTPFile; import aria.apache.commons.net.ftp.FTPFile;
import aria.apache.commons.net.ftp.FTPReply; import aria.apache.commons.net.ftp.FTPReply;
import aria.apache.commons.net.ftp.FTPSClient; import aria.apache.commons.net.ftp.FTPSClient;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.FtpUrlEntity; import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
@ -36,12 +39,15 @@ import com.arialyy.aria.exception.TaskException;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.Regular; import com.arialyy.aria.util.Regular;
import com.arialyy.aria.util.SSLContextUtil; import com.arialyy.aria.util.SSLContextUtil;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.UUID;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
/** /**
@ -79,8 +85,10 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
*/ */
protected abstract String setRemotePath(); protected abstract String setRemotePath();
@Override public void run() { @Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
TrafficStats.setThreadStatsTag(UUID.randomUUID().toString().hashCode());
FTPClient client = null; FTPClient client = null;
try { try {
client = createFtpClient(); client = createFtpClient();
@ -144,6 +152,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
mEntity.setFileSize(mSize); mEntity.setFileSize(mSize);
} }
onPreComplete(reply); onPreComplete(reply);
mEntity.update();
} catch (IOException e) { } catch (IOException e) {
failDownload(new AriaIOException(TAG, failDownload(new AriaIOException(TAG,
String.format("FTP错误信息,code:%s,msg:%s", client.getReplyCode(), client.getReplyString()), String.format("FTP错误信息,code:%s,msg:%s", client.getReplyCode(), client.getReplyString()),
@ -358,7 +367,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
* 处理FTP文件信息 * 处理FTP文件信息
* *
* @param remotePath ftp服务器文件夹路径 * @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件 * @param ftpFile ftp服务器上对应的文件
*/ */
protected void handleFile(String remotePath, FTPFile ftpFile) { protected void handleFile(String remotePath, FTPFile ftpFile) {
} }
@ -381,7 +390,8 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
this.hostName = hostName; this.hostName = hostName;
} }
@Override public void run() { @Override
public void run() {
try { try {
ips = InetAddress.getAllByName(hostName); ips = InetAddress.getAllByName(hostName);
} catch (UnknownHostException e) { } catch (UnknownHostException e) {

@ -16,6 +16,7 @@
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.os.Handler; import android.os.Handler;
import com.arialyy.aria.core.common.BaseListener; import com.arialyy.aria.core.common.BaseListener;
import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
@ -33,14 +34,16 @@ public class BaseDListener extends BaseListener<DownloadEntity, DTaskWrapper, Do
super(task, outHandler); super(task, outHandler);
} }
@Override public void onPostPre(long fileSize) { @Override
public void onPostPre(long fileSize) {
mEntity.setFileSize(fileSize); mEntity.setFileSize(fileSize);
mEntity.setConvertFileSize(CommonUtil.formatFileSize(fileSize)); mEntity.setConvertFileSize(CommonUtil.formatFileSize(fileSize));
saveData(IEntity.STATE_POST_PRE, -1); saveData(IEntity.STATE_POST_PRE, -1);
sendInState2Target(ISchedulers.POST_PRE); sendInState2Target(ISchedulers.POST_PRE);
} }
@Override public void supportBreakpoint(boolean support) { @Override
public void supportBreakpoint(boolean support) {
if (!support) { if (!support) {
sendInState2Target(ISchedulers.NO_SUPPORT_BREAK_POINT); sendInState2Target(ISchedulers.NO_SUPPORT_BREAK_POINT);
} }
@ -52,9 +55,7 @@ public class BaseDListener extends BaseListener<DownloadEntity, DTaskWrapper, Do
mEntity.setState(state); mEntity.setState(state);
if (state == IEntity.STATE_CANCEL) { if (state == IEntity.STATE_CANCEL) {
if (mEntity instanceof DownloadEntity) { CommonUtil.delTaskRecord(mEntity.getDownloadPath(), 1, mTaskWrapper.isRemoveFile());
CommonUtil.delTaskRecord(mEntity.getDownloadPath(), 1, mTaskWrapper.isRemoveFile());
}
return; return;
} else if (state == IEntity.STATE_STOP) { } else if (state == IEntity.STATE_STOP) {
mEntity.setStopTime(System.currentTimeMillis()); mEntity.setStopTime(System.currentTimeMillis());
@ -64,5 +65,6 @@ public class BaseDListener extends BaseListener<DownloadEntity, DTaskWrapper, Do
if (location > 0) { if (location > 0) {
mEntity.setCurrentProgress(location); mEntity.setCurrentProgress(location);
} }
mEntity.update();
} }
} }

@ -16,6 +16,7 @@
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.os.Handler; import android.os.Handler;
import com.arialyy.aria.core.common.BaseListener; import com.arialyy.aria.core.common.BaseListener;
import com.arialyy.aria.core.download.group.IDownloadGroupListener; import com.arialyy.aria.core.download.group.IDownloadGroupListener;
import com.arialyy.aria.core.inf.GroupSendParams; import com.arialyy.aria.core.inf.GroupSendParams;
@ -41,41 +42,49 @@ class DownloadGroupListener
mSeedEntity.groupTask = task; mSeedEntity.groupTask = task;
} }
@Override public void onSubPre(DownloadEntity subEntity) { @Override
public void onSubPre(DownloadEntity subEntity) {
sendInState2Target(ISchedulers.SUB_PRE, subEntity); sendInState2Target(ISchedulers.SUB_PRE, subEntity);
} }
@Override public void supportBreakpoint(boolean support, DownloadEntity subEntity) { @Override
public void supportBreakpoint(boolean support, DownloadEntity subEntity) {
} }
@Override public void onSubStart(DownloadEntity subEntity) { @Override
public void onSubStart(DownloadEntity subEntity) {
sendInState2Target(ISchedulers.SUB_START, subEntity); sendInState2Target(ISchedulers.SUB_START, subEntity);
} }
@Override public void onSubStop(DownloadEntity subEntity) { @Override
public void onSubStop(DownloadEntity subEntity) {
saveCurrentLocation(); saveCurrentLocation();
sendInState2Target(ISchedulers.SUB_STOP, subEntity); sendInState2Target(ISchedulers.SUB_STOP, subEntity);
} }
@Override public void onSubComplete(DownloadEntity subEntity) { @Override
public void onSubComplete(DownloadEntity subEntity) {
saveCurrentLocation(); saveCurrentLocation();
sendInState2Target(ISchedulers.SUB_COMPLETE, subEntity); sendInState2Target(ISchedulers.SUB_COMPLETE, subEntity);
} }
@Override public void onSubFail(DownloadEntity subEntity, BaseException e) { @Override
public void onSubFail(DownloadEntity subEntity, BaseException e) {
saveCurrentLocation(); saveCurrentLocation();
sendInState2Target(ISchedulers.SUB_FAIL, subEntity); sendInState2Target(ISchedulers.SUB_FAIL, subEntity);
e.printStackTrace(); e.printStackTrace();
ErrorHelp.saveError(e.getTag(), "", ALog.getExceptionString(e)); ErrorHelp.saveError(e.getTag(), "", ALog.getExceptionString(e));
} }
@Override public void onSubCancel(DownloadEntity subEntity) { @Override
public void onSubCancel(DownloadEntity subEntity) {
saveCurrentLocation(); saveCurrentLocation();
sendInState2Target(ISchedulers.SUB_CANCEL, subEntity); sendInState2Target(ISchedulers.SUB_CANCEL, subEntity);
} }
@Override public void onSubRunning(DownloadEntity subEntity) { @Override
public void onSubRunning(DownloadEntity subEntity) {
sendInState2Target(ISchedulers.SUB_RUNNING, subEntity); sendInState2Target(ISchedulers.SUB_RUNNING, subEntity);
} }
@ -107,24 +116,25 @@ class DownloadGroupListener
mEntity.update(); mEntity.update();
} }
@Override public void onPostPre(long fileSize) { @Override
public void onPostPre(long fileSize) {
mEntity.setFileSize(fileSize); mEntity.setFileSize(fileSize);
mEntity.setConvertFileSize(CommonUtil.formatFileSize(fileSize)); mEntity.setConvertFileSize(CommonUtil.formatFileSize(fileSize));
saveData(IEntity.STATE_POST_PRE, -1); saveData(IEntity.STATE_POST_PRE, -1);
sendInState2Target(ISchedulers.POST_PRE); sendInState2Target(ISchedulers.POST_PRE);
} }
@Override public void supportBreakpoint(boolean support) { @Override
public void supportBreakpoint(boolean support) {
} }
@Override protected void saveData(int state, long location) { @Override
protected void saveData(int state, long location) {
mTaskWrapper.setState(state); mTaskWrapper.setState(state);
mEntity.setState(state); mEntity.setState(state);
if (state == IEntity.STATE_CANCEL) { if (state == IEntity.STATE_CANCEL) {
if (mEntity instanceof DownloadGroupEntity) { CommonUtil.delGroupTaskRecord(mTaskWrapper.isRemoveFile(), mEntity);
CommonUtil.delGroupTaskRecord(mTaskWrapper.isRemoveFile(), mEntity);
}
return; return;
} else if (state == IEntity.STATE_STOP) { } else if (state == IEntity.STATE_STOP) {
mEntity.setStopTime(System.currentTimeMillis()); mEntity.setStopTime(System.currentTimeMillis());
@ -134,5 +144,6 @@ class DownloadGroupListener
if (location > 0) { if (location > 0) {
mEntity.setCurrentProgress(location); mEntity.setCurrentProgress(location);
} }
mEntity.update();
} }
} }

@ -287,7 +287,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return {@code true}存在{@code false} 不存在 * @return {@code true}存在{@code false} 不存在
*/ */
public boolean taskExists(String downloadUrl) { public boolean taskExists(String downloadUrl) {
return DbEntity.checkDataExist(DTaskWrapper.class, "url=?", downloadUrl); return DbEntity.checkDataExist(DownloadEntity.class, "url=?", downloadUrl);
} }
/** /**

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import android.net.TrafficStats;
import android.os.Process; import android.os.Process;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
@ -44,6 +45,7 @@ import java.net.URLEncoder;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID;
/** /**
* 下载文件信息获取 * 下载文件信息获取
@ -67,6 +69,7 @@ public class HttpFileInfoThread implements Runnable {
@Override public void run() { @Override public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
TrafficStats.setThreadStatsTag(UUID.randomUUID().toString().hashCode());
HttpURLConnection conn = null; HttpURLConnection conn = null;
try { try {
URL url = ConnectionHelp.handleUrl(mEntity.getUrl(), mTaskDelegate); URL url = ConnectionHelp.handleUrl(mEntity.getUrl(), mTaskDelegate);
@ -233,6 +236,7 @@ public class HttpFileInfoThread implements Runnable {
CompleteInfo info = new CompleteInfo(code); CompleteInfo info = new CompleteInfo(code);
onFileInfoCallback.onComplete(mEntity.getUrl(), info); onFileInfoCallback.onComplete(mEntity.getUrl(), info);
} }
mEntity.update();
} }
} }

@ -16,6 +16,7 @@
package com.arialyy.aria.core.download.group; package com.arialyy.aria.core.download.group;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.config.Configuration; import com.arialyy.aria.core.config.Configuration;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
@ -61,7 +62,7 @@ public abstract class AbsGroupUtil implements IUtil, Runnable {
mUpdateInterval = Configuration.getInstance().downloadCfg.getUpdateInterval(); mUpdateInterval = Configuration.getInstance().downloadCfg.getUpdateInterval();
mState = new GroupRunState(groupWrapper.getKey(), mListener, mState = new GroupRunState(groupWrapper.getKey(), mListener,
groupWrapper.getSubTaskWrapper().size(), mSubQueue); groupWrapper.getSubTaskWrapper().size(), mSubQueue);
mScheduler = new Handler(SimpleSchedulers.newInstance(mState)); mScheduler = new Handler(Looper.getMainLooper(), SimpleSchedulers.newInstance(mState));
initState(); initState();
} }

@ -44,5 +44,6 @@ class BaseUListener extends BaseListener<UploadEntity, UTaskWrapper, UploadTask>
} else if (location > 0) { } else if (location > 0) {
mEntity.setCurrentProgress(location); mEntity.setCurrentProgress(location);
} }
mEntity.update();
} }
} }

@ -1,12 +1,12 @@
apply plugin: 'bintray-release' apply plugin: 'com.novoda.bintray-release'
publish { publish {
artifactId = 'aria-annotations' artifactId = 'aria-annotations'
userOrg = rootProject.userOrg userOrg = rootProject.ext.userOrg
groupId = rootProject.groupId groupId = rootProject.ext.groupId
// uploadName = rootProject.uploadName // uploadName = rootProject.uploadName
uploadName = 'AriaAnnotations' uploadName = 'AriaAnnotations'
publishVersion = rootProject.publishVersion publishVersion = rootProject.ext.publishVersion
description = rootProject.description desc = rootProject.ext.desc
website = rootProject.website website = rootProject.ext.website
licences = rootProject.licences licences = rootProject.ext.licences
} }

@ -22,7 +22,7 @@ import java.lang.annotation.Target;
/** /**
* Created by lyy on 2017/6/6. * Created by lyy on 2017/6/6.
* Aria下载事件被注解的方法中参数仅能有一个参数类型为{@link com.arialyy.aria.core.download.DownloadTask} * Aria下载事件被注解的方法中参数仅能有一个参数类型为 com.arialyy.aria.core.download.DownloadTask
* <pre> * <pre>
* <code> * <code>
* {@literal @}Download.onPre * {@literal @}Download.onPre
@ -37,77 +37,77 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) public @interface Download { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) public @interface Download {
/** /**
* {@code @Download.onPre}注解下载队列已经满了继续创建新任务将会回调该方法 * "@Download.onPre"注解下载队列已经满了继续创建新任务将会回调该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onWait{ @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onWait{
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Download.onPre}注解在预处理完成时Aria会调用该方法 * "@Download.onPre"注解在预处理完成时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onPre { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onPre {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Download.onTaskPre}注解在任务预处理完成时Aria会调用该方法 * "@Download.onTaskPre"注解在任务预处理完成时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskPre { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskPre {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Download.onTaskResume}注解在任务恢复下载时Aria会调用该方法 * "@Download.onTaskResume"注解在任务恢复下载时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskResume { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskResume {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Download.onTaskStart}注解在任务开始下载时Aria会调用该方法 * "@Download.onTaskStart"注解在任务开始下载时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStart { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStart {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Download.onTaskStop}注解在任务停止时Aria会调用该方法 * "@Download.onTaskStop"注解在任务停止时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStop { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStop {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Download.onTaskCancel}l注解在任务取消时Aria会调用该方法 * "@Download.onTaskCancel}l注解在任务取消时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskCancel { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskCancel {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Download.onTaskFail)注解在任务预失败时Aria会调用该方法 * "@Download.onTaskFail)注解在任务预失败时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskFail { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskFail {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Download.onTaskComplete}注解在任务完成时Aria会调用该方法 * "@Download.onTaskComplete"注解在任务完成时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskComplete { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskComplete {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Download.onTaskRunning}注解在任务正在下载Aria会调用该方法 * "@Download.onTaskRunning"注解在任务正在下载Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskRunning { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskRunning {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Download.onNoSupportBreakPoint}注解如果该任务不支持断点Aria会调用该方法 * "@Download.onNoSupportBreakPoint"注解如果该任务不支持断点Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD)
@interface onNoSupportBreakPoint { @interface onNoSupportBreakPoint {

@ -22,7 +22,7 @@ import java.lang.annotation.Target;
/** /**
* Created by lyy on 2017/6/6. * Created by lyy on 2017/6/6.
* Aria下载事件被注解的方法中参数仅能有一个参数类型为{@link com.arialyy.aria.core.download.DownloadGroupTask} * Aria下载事件被注解的方法中参数仅能有一个参数类型为 com.arialyy.aria.core.download.DownloadGroupTask
* <pre> * <pre>
* <code> * <code>
* {@literal @}DownloadGroup.onPre(groupHash) * {@literal @}DownloadGroup.onPre(groupHash)
@ -46,70 +46,70 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) public @interface DownloadGroup { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) public @interface DownloadGroup {
/** /**
* {@code @Download.onPre}队列已经满了继续创建新任务将会回调该方法 * " @Download.onPre"队列已经满了继续创建新任务将会回调该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onWait { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onWait {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @DownloadGroup.onPre}在预处理完成时Aria会调用该方法 * " @DownloadGroup.onPre"在预处理完成时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onPre { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onPre {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @DownloadGroup.onTaskPre}在任务预处理完成时Aria会调用该方法 * " @DownloadGroup.onTaskPre"在任务预处理完成时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskPre { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskPre {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @DownloadGroup.onTaskResume}在任务恢复下载时Aria会调用该方法 * " @DownloadGroup.onTaskResume"在任务恢复下载时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskResume { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskResume {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @DownloadGroup.onTaskStart}在任务开始下载时Aria会调用该方法 * " @DownloadGroup.onTaskStart"在任务开始下载时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStart { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStart {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @DownloadGroup.onTaskStop}在任务停止时Aria会调用该方法 * " @DownloadGroup.onTaskStop"在任务停止时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStop { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStop {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @DownloadGroup.onTaskCancel}l注解在任务取消时Aria会调用该方法 * " @DownloadGroup.onTaskCancel}l注解在任务取消时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskCancel { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskCancel {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @DownloadGroup.onTaskFail)注解在任务预失败时Aria会调用该方法 * " @DownloadGroup.onTaskFail)注解在任务预失败时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskFail { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskFail {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @DownloadGroup.onTaskComplete}在任务完成时Aria会调用该方法 * " @DownloadGroup.onTaskComplete"在任务完成时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskComplete { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskComplete {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @DownloadGroup.onTaskRunning}在任务正在下载Aria会调用该方法 * " @DownloadGroup.onTaskRunning"在任务正在下载Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskRunning { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskRunning {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };

@ -22,7 +22,7 @@ import java.lang.annotation.Target;
/** /**
* Created by lyy on 2017/6/6. * Created by lyy on 2017/6/6.
* Aria下载事件被注解的方法中参数仅能有一个参数类型为{@link com.arialyy.aria.core.upload.UploadTask} * Aria下载事件被注解的方法中参数仅能有一个参数类型为com.arialyy.aria.core.upload.UploadTask
* <pre> * <pre>
* <code> * <code>
* {@literal @}Upload.onPre * {@literal @}Upload.onPre
@ -37,70 +37,70 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) public @interface Upload { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) public @interface Upload {
/** /**
* {@code @Download.onPre}注解队列已经满了继续创建新任务将会回调该方法 * "@Upload.onWait" 注解队列已经满了继续创建新任务将会回调该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onWait { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onWait {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Upload.onPre}注解在预处理完成时Aria会调用该方法 * "@Upload.onPre"注解在预处理完成时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onPre { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onPre {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Upload.onTaskResume}注解在任务恢复下载时Aria会调用该方法 * "@Upload.onTaskResume"注解在任务恢复下载时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskResume { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskResume {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Upload.onTaskStart}注解在任务开始下载时Aria会调用该方法 * "@Upload.onTaskStart"注解在任务开始下载时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStart { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStart {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Upload.onTaskStop}注解在任务停止时Aria会调用该方法 * "@Upload.onTaskStop"注解在任务停止时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStop { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskStop {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Upload.onTaskCancel}l注解在任务取消时Aria会调用该方法 * "@Upload.onTaskCancel"注解在任务取消时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskCancel { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskCancel {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Upload.onTaskFail)注解在任务预失败时Aria会调用该方法 * "@Upload.onTaskFail"注解在任务预失败时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskFail { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskFail {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Upload.onTaskComplete}注解在任务完成时Aria会调用该方法 * "@Upload.onTaskComplete"注解在任务完成时Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskComplete { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskComplete {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Upload.onTaskRunning}注解在任务正在下载Aria会调用该方法 * "@Upload.onTaskRunning"注解在任务正在下载Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskRunning { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onTaskRunning {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };
} }
/** /**
* {@code @Upload.onNoSupportBreakPoint}注解如果该任务不支持断点Aria会调用该方法 * "@Upload.onNoSupportBreakPoint"注解如果该任务不支持断点Aria会调用该方法
*/ */
@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onNoSupportBreakPoint { @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface onNoSupportBreakPoint {
String[] value() default { AriaConstance.NO_URL }; String[] value() default { AriaConstance.NO_URL };

@ -1,12 +1,12 @@
apply plugin: 'bintray-release' apply plugin: 'com.novoda.bintray-release'
publish { publish {
artifactId = 'aria-compiler' artifactId = 'aria-compiler'
userOrg = rootProject.userOrg userOrg = rootProject.ext.userOrg
groupId = rootProject.groupId groupId = rootProject.ext.groupId
// uploadName = rootProject.uploadName // uploadName = rootProject.uploadName
uploadName = 'AriaCompiler' uploadName = 'AriaCompiler'
publishVersion = rootProject.publishVersion publishVersion = rootProject.ext.publishVersion
description = rootProject.description desc = rootProject.ext.desc
website = rootProject.website website = rootProject.ext.website
licences = rootProject.licences licences = rootProject.ext.licences
} }

@ -7,11 +7,11 @@ sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7 targetCompatibility = JavaVersion.VERSION_1_7
dependencies { dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.google.auto:auto-common:0.6' implementation 'com.google.auto:auto-common:0.6'
compile 'com.google.auto.service:auto-service:1.0-rc2' implementation 'com.google.auto.service:auto-service:1.0-rc2'
compile 'com.squareup:javapoet:1.9.0' implementation 'com.squareup:javapoet:1.9.0'
compile project(':AriaAnnotations') implementation project(':AriaAnnotations')
} }
apply from: 'bintray-release.gradle' apply from: 'bintray-release.gradle'

@ -1,11 +1,11 @@
apply plugin: 'bintray-release' apply plugin: 'com.novoda.bintray-release'
publish { publish {
artifactId = 'aria-ftp-plug' artifactId = 'aria-ftp-plug'
userOrg = rootProject.userOrg userOrg = rootProject.ext.userOrg
groupId = rootProject.groupId groupId = rootProject.ext.groupId
uploadName = 'FtpPlug' uploadName = 'FtpPlug'
publishVersion = rootProject.publishVersion publishVersion = rootProject.ext.publishVersion
description = rootProject.description desc = rootProject.ext.desc
website = rootProject.website website = rootProject.ext.website
licences = rootProject.licences licences = rootProject.ext.licences
} }

@ -8,7 +8,7 @@ sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7 targetCompatibility = JavaVersion.VERSION_1_7
dependencies { dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
} }
//apply from: 'bintray-release.gradle' //apply from: 'bintray-release.gradle'

@ -1,5 +1,10 @@
## 开发日志 ## 开发日志
+ v_3.6 + v_3.6.2
- fix bug https://github.com/AriaLyy/Aria/issues/368
- 增加gradle 5.0支持
+ v_3.6.1 (2019/3/5)
- fix bug https://github.com/AriaLyy/Aria/issues/367
+ v_3.6 (2019/2/27)
- 优化数据库写入\修改的速度 - 优化数据库写入\修改的速度
- 精减任务实体的存储 - 精减任务实体的存储
- 增加下载组合任务的配置 - 增加下载组合任务的配置

@ -33,17 +33,19 @@ Aria有以下特点:
[![Compiler](https://api.bintray.com/packages/arialyy/maven/AriaCompiler/images/download.svg)](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion) [![Compiler](https://api.bintray.com/packages/arialyy/maven/AriaCompiler/images/download.svg)](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion)
```java ```java
compile 'com.arialyy.aria:aria-core:3.6' api 'com.arialyy.aria:aria-core:3.6'
annotationProcessor 'com.arialyy.aria:aria-compiler:3.6' annotationProcessor 'com.arialyy.aria:aria-compiler:3.6'
``` ```
如果出现android support,请将 `compile 'com.arialyy.aria:aria-core:<last-version>'`替换为 如果出现android support依赖错误,请将 `compile 'com.arialyy.aria:aria-core:<last-version>'`替换为
``` ```
compile('com.arialyy.aria:aria-core:<last-version>'){ api('com.arialyy.aria:aria-core:<last-version>'){
exclude group: 'com.android.support' exclude group: 'com.android.support'
} }
``` ```
如果你使用的是kotlin,请使用kotlin官方提供的方法配置apt,[kotlin kapt官方配置传送门](https://www.kotlincn.net/docs/reference/kapt.html) 如果你使用的是kotlin,请使用kotlin官方提供的方法配置apt,[kotlin kapt官方配置传送门](https://www.kotlincn.net/docs/reference/kapt.html)
__注意:3.5.4以下版本升级时,需要更新[配置文件]!!(https://aria.laoyuyu.me/aria_doc/start/config.html)__
*** ***
## 使用 ## 使用
由于Aria涉及到文件和网络的操作,因此需要你在manifest文件中添加以下权限,如果你希望在6.0以上的系统中使用Aria,那么你需要动态向安卓系统申请文件系统读写权限,[如何使用安卓系统权限](https://developer.android.com/training/permissions/index.html?hl=zh-cn) 由于Aria涉及到文件和网络的操作,因此需要你在manifest文件中添加以下权限,如果你希望在6.0以上的系统中使用Aria,那么你需要动态向安卓系统申请文件系统读写权限,[如何使用安卓系统权限](https://developer.android.com/training/permissions/index.html?hl=zh-cn)

@ -4,13 +4,13 @@ apply plugin: 'kotlin-android-extensions'
//apply plugin: 'kotlin-kapt' //apply plugin: 'kotlin-kapt'
android { android {
compileSdkVersion 23 compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion '26.0.2' buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig { defaultConfig {
applicationId "com.arialyy.simple" applicationId "com.arialyy.simple"
minSdkVersion 15 minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion 23 targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
multiDexEnabled true multiDexEnabled true
@ -41,20 +41,16 @@ android {
} }
dependencies { dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.+' implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
compile 'com.android.support:design:23.+' implementation "com.android.support:design:${rootProject.ext.supportLibVersion}"
compile 'com.jakewharton:butterknife:7.0.1' api project(':Aria')
compile 'com.google.code.gson:gson:2.7' annotationProcessor project(':AriaCompiler')
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.arialyy.frame:MVVM2:2.2.0'
compile project(':Aria')
compile project(':AriaCompiler')
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
// compile 'com.arialyy.aria:aria-core:3.3.16' // compile 'com.arialyy.aria:aria-core:3.3.16'
// annotationProcessor 'com.arialyy.aria:aria-compiler:3.3.16' // annotationProcessor 'com.arialyy.aria:aria-compiler:3.3.16'
debugCompile 'com.amitshekhar.android:debug-db:1.0.0' debugApi 'com.amitshekhar.android:debug-db:1.0.0'
implementation project(':AppFrame')
} }
repositories { repositories {
mavenCentral() mavenCentral()

@ -15,4 +15,4 @@
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true

@ -19,8 +19,6 @@ package com.arialyy.simple;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import butterknife.OnClick;
import com.arialyy.aria.core.Aria;
import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivityMainBinding; import com.arialyy.simple.databinding.ActivityMainBinding;
import com.arialyy.simple.download.DownloadActivity; import com.arialyy.simple.download.DownloadActivity;
@ -33,24 +31,29 @@ import com.arialyy.simple.upload.HttpUploadActivity;
/** /**
* Created by lyy on 2017/3/1. * Created by lyy on 2017/3/1.
*/ */
public class MainActivity extends BaseActivity<ActivityMainBinding> { public class MainActivity extends BaseActivity<ActivityMainBinding>
implements View.OnClickListener {
@Override protected void init(Bundle savedInstanceState) { @Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState); super.init(savedInstanceState);
setSupportActionBar(mBar); setSupportActionBar(mBar);
mBar.setTitle("Aria Demo"); mBar.setTitle("Aria Demo");
getSupportActionBar().setDisplayHomeAsUpEnabled(false); getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getBinding().download.setOnClickListener(this);
getBinding().upload.setOnClickListener(this);
getBinding().downloadTaskGroup.setOnClickListener(this);
getBinding().ftpDownload.setOnClickListener(this);
getBinding().ftpDirDownload.setOnClickListener(this);
getBinding().ftpUpload.setOnClickListener(this);
getBinding().kotlinDownload.setOnClickListener(this);
} }
@Override protected int setLayoutId() { @Override protected int setLayoutId() {
return R.layout.activity_main; return R.layout.activity_main;
} }
@OnClick({ @Override
R.id.download, R.id.upload, R.id.download_task_group, R.id.ftp_download, public void onClick(View view) {
R.id.ftp_dir_download, R.id.ftp_upload, R.id.kotlin_download
}) public void funcation(View view) {
switch (view.getId()) { switch (view.getId()) {
case R.id.download: case R.id.download:
startActivity(new Intent(this, DownloadActivity.class)); startActivity(new Intent(this, DownloadActivity.class));

@ -20,7 +20,6 @@ import android.databinding.ViewDataBinding;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.view.MenuItem; import android.view.MenuItem;
import butterknife.Bind;
import com.arialyy.frame.core.AbsActivity; import com.arialyy.frame.core.AbsActivity;
import com.arialyy.frame.util.AndroidVersionUtil; import com.arialyy.frame.util.AndroidVersionUtil;
import com.arialyy.simple.R; import com.arialyy.simple.R;
@ -32,7 +31,7 @@ import com.arialyy.simple.common.MsgDialog;
public abstract class BaseActivity<VB extends ViewDataBinding> extends AbsActivity<VB> public abstract class BaseActivity<VB extends ViewDataBinding> extends AbsActivity<VB>
implements Toolbar.OnMenuItemClickListener { implements Toolbar.OnMenuItemClickListener {
@Bind(R.id.toolbar) protected Toolbar mBar; protected Toolbar mBar;
@Override protected void onCreate(Bundle savedInstanceState) { @Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -43,16 +42,20 @@ public abstract class BaseActivity<VB extends ViewDataBinding> extends AbsActivi
@Override protected void init(Bundle savedInstanceState) { @Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState); super.init(savedInstanceState);
mBar = findViewById(R.id.toolbar);
setSupportActionBar(mBar); setSupportActionBar(mBar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mBar.setOnMenuItemClickListener(this); mBar.setOnMenuItemClickListener(this);
} }
protected void setTile(String title){ protected void setTile(String title) {
if (mBar == null) {
mBar = findViewById(R.id.toolbar);
}
mBar.setTitle(title); mBar.setTitle(title);
} }
protected void showMsgDialog(String title, String msg){ protected void showMsgDialog(String title, String msg) {
MsgDialog dialog = new MsgDialog(this, title, msg); MsgDialog dialog = new MsgDialog(this, title, msg);
dialog.show(getSupportFragmentManager(), "msg_dialog"); dialog.show(getSupportFragmentManager(), "msg_dialog");
} }

@ -19,7 +19,6 @@ package com.arialyy.simple.base;
import android.app.Application; import android.app.Application;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.os.Build;
import android.os.StrictMode; import android.os.StrictMode;
import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.Aria;
import com.arialyy.frame.core.AbsFrame; import com.arialyy.frame.core.AbsFrame;
@ -38,17 +37,13 @@ public class BaseApplication extends Application {
INSTANCE = this; INSTANCE = this;
AbsFrame.init(this); AbsFrame.init(this);
Aria.init(this); Aria.init(this);
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy( StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
//.detectLeakedSqlLiteObjects()
//.detectLeakedClosableObjects()
.detectAll() .detectAll()
.penaltyDeath()
.penaltyLog() .penaltyLog()
.build(); .build());
StrictMode.setVmPolicy(policy); StrictMode.setThreadPolicy(
new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
} }
registerReceiver(new ConnectionChangeReceiver(), registerReceiver(new ConnectionChangeReceiver(),

@ -20,7 +20,6 @@ import android.support.v7.widget.RecyclerView;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.View; import android.view.View;
import butterknife.ButterKnife;
/** /**
* Created by lyy on 2015/12/3. * Created by lyy on 2015/12/3.
@ -32,7 +31,7 @@ public class AbsHolder extends RecyclerView.ViewHolder {
public AbsHolder(View itemView) { public AbsHolder(View itemView) {
super(itemView); super(itemView);
ButterKnife.bind(this, itemView); mView = itemView;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

@ -16,8 +16,6 @@
package com.arialyy.simple.base.adapter; package com.arialyy.simple.base.adapter;
import android.content.Context; import android.content.Context;
import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;

@ -17,8 +17,7 @@ package com.arialyy.simple.common;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.os.Bundle; import android.os.Bundle;
import butterknife.OnClick; import android.view.View;
import com.arialyy.frame.util.show.T;
import com.arialyy.simple.R; import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseDialog; import com.arialyy.simple.base.BaseDialog;
import com.arialyy.simple.databinding.DialogMsgBinding; import com.arialyy.simple.databinding.DialogMsgBinding;
@ -40,14 +39,14 @@ import com.arialyy.simple.databinding.DialogMsgBinding;
super.init(savedInstanceState); super.init(savedInstanceState);
getBinding().setTitle(mTitle); getBinding().setTitle(mTitle);
getBinding().setMsg(mMsg); getBinding().setMsg(mMsg);
getBinding().enter.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
dismiss();
}
});
} }
@Override protected int setLayoutId() { @Override protected int setLayoutId() {
return R.layout.dialog_msg; return R.layout.dialog_msg;
} }
@OnClick(R.id.enter)
public void close(){
dismiss();
}
} }

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

Loading…
Cancel
Save